Merge branch 'master' of https://gitee.com/ruitao_admin/godoos
This commit is contained in:
commit
86dc81a78c
23 changed files with 1526 additions and 203 deletions
|
|
@ -1 +1,5 @@
|
|||
## 变更记录
|
||||
- 2024-08-02
|
||||
1. 修复桌面更换背景文字颜色问题
|
||||
2. 修复安装插件没有配置binPath的问题
|
||||
3. 新增linux环境下获取安装命令的方法
|
||||
51
README.en.md
51
README.en.md
|
|
@ -13,32 +13,35 @@ English | [简体中文](README.md)
|
|||
|
||||
[FAQ](./docs/Faq.md) | [API](./docs/Api.md) | [AppStore](./docs/Store.en.md)
|
||||
|
||||
### Install
|
||||
|
||||
[![Windows][Windows-image]][Windows-url]
|
||||
[![MacOS][MacOS-image]][MacOS-url]
|
||||
[![Linux][Linux-image]][Linux-url]
|
||||
|
||||
|
||||
[license-image]: ./docs/img/license_%20MIT.svg
|
||||
|
||||
[license-url]: https://spdx.org/licenses/MIT.html
|
||||
|
||||
|
||||
[Windows-image]: ./docs/img/Windows.svg
|
||||
|
||||
[Windows-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-windows.exe
|
||||
|
||||
[MacOS-image]: ./docs/img/MacOS.svg
|
||||
|
||||
[MacOS-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip
|
||||
|
||||
[Linux-image]: ./docs/img/Linux.svg
|
||||
|
||||
[Linux-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-linux-amd64.zip
|
||||
|
||||
</div>
|
||||
|
||||
### 👇 Download and Install
|
||||
|
||||
|
||||
1. ![Download for MacOS][Windows-image] **Windows User**:
|
||||
|
||||
- Windows (AMD64) [**gitee Download**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-amd64-installer.exe) | [**github Download**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-amd64-installer.exe)
|
||||
|
||||
- Windows (ARM64) [**gitee Download**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-arm64-installer.exe) | [**github Download**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-arm64-installer.exe)
|
||||
|
||||
|
||||
2. ![Download for MacOS][MacOS-image] **MacOS User**:
|
||||
|
||||
- MacOS (AMD64) [**gitee Download**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip) | [**github Download**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip)
|
||||
|
||||
- MacOS (ARM64) [**gitee Download**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip) | [**github Download**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip)
|
||||
|
||||
3. ![Download for Linux][Linux-image] **Linux User**:
|
||||
|
||||
- Linux (AMD64) [**gitee Download**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-linux-amd64.zip) | [**github Download**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip)
|
||||
|
||||
<!-- 图标和链接 -->
|
||||
[Windows-image]: ./docs/img/Windows.svg
|
||||
[MacOS-image]: ./docs/img/MacOS.svg
|
||||
[Linux-image]: ./docs/img/Linux.svg
|
||||
[license-image]: ./docs/img/license_%20MIT.svg
|
||||
[license-url]: https://spdx.org/licenses/MIT.html
|
||||
|
||||
## Highlights
|
||||
- ***No need for internet connection, fully open source***
|
||||
- ***Zero configuration, no registration required, download and use immediately***
|
||||
|
|
|
|||
57
README.md
57
README.md
|
|
@ -13,33 +13,36 @@
|
|||
|
||||
[FAQ](./docs/Faq.md) | [API](./docs/Api.md) | [应用开发](./docs/Store.md)
|
||||
|
||||
|
||||
### 📚 安装
|
||||
|
||||
[![Windows][Windows-image]][Windows-url]
|
||||
[![MacOS][MacOS-image]][MacOS-url]
|
||||
[![Linux][Linux-image]][Linux-url]
|
||||
|
||||
|
||||
[license-image]: ./docs/img/license_%20MIT.svg
|
||||
|
||||
[license-url]: https://spdx.org/licenses/MIT.html
|
||||
|
||||
|
||||
[Windows-image]: ./docs/img/Windows.svg
|
||||
|
||||
[Windows-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-amd64-installer.exe
|
||||
|
||||
[MacOS-image]: ./docs/img/MacOS.svg
|
||||
|
||||
[MacOS-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip
|
||||
|
||||
[Linux-image]: ./docs/img/Linux.svg
|
||||
|
||||
[Linux-url]: https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-linux-amd64.zip
|
||||
|
||||
</div>
|
||||
|
||||
### 👇 下载安装
|
||||
|
||||
|
||||
1. ![Download for MacOS][Windows-image] **Windows 用户**:
|
||||
|
||||
- Windows (AMD64) [**国内下载**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-amd64-installer.exe) | [**github下载**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-amd64-installer.exe)
|
||||
|
||||
- Windows (ARM64) [**国内下载**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-arm64-installer.exe) | [**github下载**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-arm64-installer.exe)
|
||||
|
||||
|
||||
2. ![Download for MacOS][MacOS-image] **MacOS 用户**:
|
||||
|
||||
- MacOS (AMD64) [**国内下载**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip) | [**github下载**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-amd64.zip)
|
||||
|
||||
- MacOS (ARM64) [**国内下载**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip) | [**github下载**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip)
|
||||
|
||||
3. ![Download for Linux][Linux-image] **Linux 用户**:
|
||||
|
||||
- Linux (AMD64) [**国内下载**](https://gitee.com/ruitao_admin/godoos/releases/download/v1.0.0/godoos-linux-amd64.zip) | [**github下载**](https://github.com/phpk/godoos/releases/download/v1.0.0/godoos-macos-arm64.zip)
|
||||
|
||||
|
||||
<!-- 图标和链接 -->
|
||||
[Windows-image]: ./docs/img/Windows.svg
|
||||
[MacOS-image]: ./docs/img/MacOS.svg
|
||||
[Linux-image]: ./docs/img/Linux.svg
|
||||
[license-image]: ./docs/img/license_%20MIT.svg
|
||||
[license-url]: https://spdx.org/licenses/MIT.html
|
||||
|
||||
## 💝 亮点
|
||||
- ***无需联网使用,全开源***
|
||||
- ***零配置,无需注册,下载即用***
|
||||
|
|
@ -50,6 +53,10 @@
|
|||
- ***支持多平台,Windows、Linux、MacOS***
|
||||
- ***完善的应用商店体系,简单学习一下[应用商店配置](./docs/Store.md)即可开发出复杂的应用***
|
||||
|
||||
## 💖 开源地址
|
||||
- [Gitee](https://gitee.com/ruitao_admin/godoos)
|
||||
- [Github](https://github.com/phpk/godoos)
|
||||
|
||||
## 🚀 演示视频
|
||||
- [全程操作](https://www.bilibili.com/video/BV1NdvaeEEz3/?vd_source=739e0e59aeefdb2e9f760e5037d00245)
|
||||
|
||||
|
|
|
|||
29
build.linux.sh
Normal file → Executable file
29
build.linux.sh
Normal file → Executable file
|
|
@ -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"
|
||||
|
|
@ -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
generated
13
frontend/package-lock.json
generated
|
|
@ -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"
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 209 KiB |
BIN
frontend/public/image/bg/bg7.jpg
Normal file
BIN
frontend/public/image/bg/bg7.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
frontend/public/image/bg/bg8.jpg
Normal file
BIN
frontend/public/image/bg/bg8.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 367 KiB |
BIN
frontend/public/image/bg/bg9.jpg
Normal file
BIN
frontend/public/image/bg/bg9.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -1,15 +1,19 @@
|
|||
<template>
|
||||
<div class="desk-group">
|
||||
<FileList :on-chosen="props.onChosen" :on-open="openapp" :file-list="appList"></FileList>
|
||||
<FileList
|
||||
:on-chosen="props.onChosen"
|
||||
:on-open="openapp"
|
||||
:file-list="appList"
|
||||
></FileList>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { mountEvent } from '@/system/event';
|
||||
import { useSystem } from '@/system/index.ts';
|
||||
import { useAppOpen } from '@/hook/useAppOpen';
|
||||
import { onMounted } from 'vue';
|
||||
import { mountEvent } from "@/system/event";
|
||||
import { useSystem } from "@/system/index.ts";
|
||||
import { useAppOpen } from "@/hook/useAppOpen";
|
||||
import { onMounted } from "vue";
|
||||
|
||||
const { openapp, appList } = useAppOpen('apps');
|
||||
const { openapp, appList } = useAppOpen("apps");
|
||||
const props = defineProps({
|
||||
onChosen: {
|
||||
type: Function,
|
||||
|
|
@ -17,7 +21,7 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
onMounted(() => {
|
||||
mountEvent('file.props.edit', async () => {
|
||||
mountEvent("file.props.edit", async () => {
|
||||
useSystem().initAppList();
|
||||
});
|
||||
});
|
||||
|
|
@ -28,5 +32,15 @@ onMounted(() => {
|
|||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
height: 100%;
|
||||
// 应用镂空效果
|
||||
color: transparent; /* 文字颜色设为透明 */
|
||||
text-shadow: 0 0 0.5px white, 0 0 1px black, 0 0 2px rgba(0, 0, 0, 2); /* 多层阴影 */
|
||||
|
||||
// 重置子元素的默认样式
|
||||
> * {
|
||||
color: inherit; /* 继承颜色 */
|
||||
text-shadow: inherit; /* 继承描边效果 */
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,3 @@ const predefineColors = ref([
|
|||
"#c7158577",
|
||||
]);
|
||||
</script>
|
||||
<!-- <style>
|
||||
@import url('vue-accessible-color-picker/styles');
|
||||
</style> -->
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<template v-if="config.background.type === 'color'">
|
||||
<div class="setting-item">
|
||||
<label> </label>
|
||||
<ColorPicker v-model="config.background.color"></ColorPicker>
|
||||
<ColorPicker v-model:modelValue="config.background.color" @update:modelValue="onColorChange"></ColorPicker>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="config.background.type === 'image'">
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
v-for="(item, index) in config.background.imageList"
|
||||
:key="index"
|
||||
:class="config.background.url === item ? 'selected' : ''"
|
||||
@click="config.background.url = item"
|
||||
@click="setBg(item)"
|
||||
>
|
||||
<img :src="item" />
|
||||
</li>
|
||||
|
|
@ -49,21 +49,14 @@
|
|||
<label> </label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="setting-item">
|
||||
<label> </label>
|
||||
<el-button @click="submit" type="primary">
|
||||
{{ t("confirm") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getSystemConfig, setSystemConfig } from "@/system/config";
|
||||
import { ref, toRaw } from "vue";
|
||||
import { Dialog, t, useSystem } from "@/system";
|
||||
import { ref } from "vue";
|
||||
import { t, useSystem } from "@/system";
|
||||
const sys = useSystem();
|
||||
const items = [t("background")];
|
||||
const desktopOptions = [
|
||||
|
|
@ -78,42 +71,23 @@ const desktopOptions = [
|
|||
];
|
||||
|
||||
const activeIndex = ref(0);
|
||||
const config = ref(getSystemConfig());
|
||||
const config:any = ref(getSystemConfig());
|
||||
function setBg(item: any){
|
||||
config.value.background.url = item
|
||||
config.value.background.type = "image";
|
||||
setSystemConfig(config.value);
|
||||
sys.initBackground();
|
||||
|
||||
/** 提交背景设置 */
|
||||
async function submit() {
|
||||
const val = toRaw(config.value);
|
||||
setSystemConfig(val);
|
||||
config.value = val;
|
||||
Dialog.showMessageBox({
|
||||
message: t("save.success"),
|
||||
title: t("wallpaper"),
|
||||
type: "success",
|
||||
}).then(() => {
|
||||
//location.reload();
|
||||
sys.initBackground();
|
||||
});
|
||||
}
|
||||
|
||||
function onColorChange(color : string){
|
||||
config.value.background.color = color;
|
||||
config.value.background.type = "color";
|
||||
setSystemConfig(config.value);
|
||||
sys.initBackground();
|
||||
}
|
||||
const selectItem = (index: number) => {
|
||||
activeIndex.value = index;
|
||||
};
|
||||
// async function submitStyle() {
|
||||
// let rootStyle = system.getConfig("rootStyle");
|
||||
// rootStyle = {
|
||||
// ...rootStyle,
|
||||
// "--icon-title-color": textColor.value,
|
||||
// "--window-border-radius": winRadius.value,
|
||||
// "--theme-main-color": taskBarColor.value,
|
||||
// };
|
||||
// await system.setConfig("rootStyle", rootStyle);
|
||||
|
||||
// Dialog.showMessageBox({
|
||||
// message: t("save.success"),
|
||||
// title: t("style"),
|
||||
// type: "info",
|
||||
// });
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ async function install(item: any) {
|
|||
}
|
||||
const url = store.apiUrl + '/store/download'
|
||||
const res = await download(item, url, postData)
|
||||
console.log(res)
|
||||
//console.log(res)
|
||||
item.progress = 0
|
||||
if(res.code < 0){
|
||||
if(res.data && res.data.dependencies && res.data.dependencies.length > 0){
|
||||
const names:any = []
|
||||
|
|
@ -48,27 +49,6 @@ async function install(item: any) {
|
|||
await store.checkProgress()
|
||||
notifySuccess(t("store.installSuccess"))
|
||||
}
|
||||
|
||||
// if (item.needInstall) {
|
||||
// item.progress = 0
|
||||
// const completion = await fetch(store.apiUrl + '/store/install?name=' + item.name)
|
||||
// if (!completion.ok) {
|
||||
// notifyError(t("store.installError"))
|
||||
// return
|
||||
// }
|
||||
// const res = await completion.json()
|
||||
// if (res.code && res.code < 0) {
|
||||
// notifyError(res.message)
|
||||
// return
|
||||
// }
|
||||
// if (res.data) {
|
||||
// item.icon = res.data.icon
|
||||
// }
|
||||
// }
|
||||
|
||||
// await store.addDesktop(item);
|
||||
// await store.checkProgress()
|
||||
// notifySuccess(t("store.installSuccess"))
|
||||
}
|
||||
|
||||
async function uninstall(item: any) {
|
||||
|
|
@ -125,11 +105,11 @@ async function pauseApp(item: any) {
|
|||
if (!res.ok) {
|
||||
const msg = await res.text()
|
||||
notifyError(msg)
|
||||
return
|
||||
//return
|
||||
}
|
||||
setTimeout(async () => {
|
||||
await store.checkProgress()
|
||||
}, 1000)
|
||||
}, 3000)
|
||||
|
||||
}
|
||||
async function restartApp(item: any) {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ export const getSystemConfig = (ifset = false) => {
|
|||
'/image/bg/bg4.jpg',
|
||||
'/image/bg/bg5.jpg',
|
||||
'/image/bg/bg6.jpg',
|
||||
'/image/bg/bg7.jpg',
|
||||
'/image/bg/bg8.jpg',
|
||||
'/image/bg/bg9.jpg',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1100
godo/deps/darwin/brew-install.sh
Executable file
1100
godo/deps/darwin/brew-install.sh
Executable file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -30,22 +30,12 @@ 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)
|
||||
log.Printf("Error starting script: %v\nDetailed error: %v", err, cmd.Stderr)
|
||||
return fmt.Errorf("error starting script: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -69,9 +59,48 @@ func runStart(storeInfo StoreInfo) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
func GetRunCmd(binPath string, cmds []string) (*exec.Cmd, error) {
|
||||
var cmd *exec.Cmd
|
||||
log.Printf("run script: %s", strings.Join(cmds, " "))
|
||||
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")
|
||||
}
|
||||
log.Printf("run script: %s", strings.Join(cmds, " "))
|
||||
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 +116,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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Normal file
153
godo/store/os.go
Normal file
|
|
@ -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
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -26,7 +25,7 @@ type AllProcessesResponse struct {
|
|||
Processes []ProcessSystemInfo `json:"processes"`
|
||||
}
|
||||
|
||||
var processInfoRegex = regexp.MustCompile(`(\d+)\s+.*:\s*(\d+)\s+.*LISTEN\s+.*:(\d+)`)
|
||||
//var processInfoRegex = regexp.MustCompile(`(\d+)\s+.*:\s*(\d+)\s+.*LISTEN\s+.*:(\d+)`)
|
||||
|
||||
func listAllProcesses() ([]ProcessSystemInfo, error) {
|
||||
osType := runtime.GOOS
|
||||
|
|
@ -37,7 +36,7 @@ func listAllProcesses() ([]ProcessSystemInfo, error) {
|
|||
|
||||
switch osType {
|
||||
case "darwin", "linux":
|
||||
cmd = exec.Command("lsof", "-i", "-n", "-P")
|
||||
cmd = exec.Command("lsof", "-i")
|
||||
case "windows":
|
||||
cmd = exec.Command("netstat", "-ano")
|
||||
cmd = SetHideConsoleCursor(cmd)
|
||||
|
|
@ -50,31 +49,34 @@ func listAllProcesses() ([]ProcessSystemInfo, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list all processes: %v", err)
|
||||
}
|
||||
//lsofRegex := regexp.MustCompile(`(\d+)\s+(\S+\s+\S+)\s+(\d+)\s+(\w+)\s+IPv4\s+(\w+)\s+(\w+)\s+TCP\s+(\S+)\->\s+(\S+)\s+\((\w+)\)`)
|
||||
|
||||
processes := make([]ProcessSystemInfo, 0)
|
||||
|
||||
// 初始化映射用于去重
|
||||
seenPIDs := make(map[int]bool)
|
||||
// 解析输出
|
||||
switch osType {
|
||||
case "darwin", "linux":
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(output)) // 使用bufio.Scanner
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(output))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
matches := processInfoRegex.FindStringSubmatch(line)
|
||||
if matches != nil {
|
||||
pid, _ := strconv.Atoi(matches[1])
|
||||
port, _ := strconv.Atoi(matches[3])
|
||||
processName, err := getProcessName(osType, pid)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get process name for PID %d: %v", pid, err)
|
||||
continue
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 9 && fields[7] == "TCP" {
|
||||
// 解析 PID 和其他字段
|
||||
pid, _ := strconv.Atoi(fields[1])
|
||||
name := fields[0]
|
||||
// 解析本地端口
|
||||
localPortStr := strings.Split(fields[8], ":")[1]
|
||||
localPort, _ := strconv.Atoi(localPortStr)
|
||||
if !seenPIDs[pid] {
|
||||
seenPIDs[pid] = true
|
||||
processes = append(processes, ProcessSystemInfo{
|
||||
PID: pid,
|
||||
Port: localPort,
|
||||
Proto: "TCP",
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
processes = append(processes, ProcessSystemInfo{
|
||||
PID: pid,
|
||||
Port: port,
|
||||
Proto: matches[2],
|
||||
Name: processName,
|
||||
})
|
||||
}
|
||||
}
|
||||
case "windows":
|
||||
|
|
@ -101,12 +103,15 @@ func listAllProcesses() ([]ProcessSystemInfo, error) {
|
|||
log.Printf("Failed to convert port to integer: %v", err)
|
||||
continue
|
||||
}
|
||||
processes = append(processes, ProcessSystemInfo{
|
||||
PID: pid,
|
||||
Port: portInt,
|
||||
Proto: fields[0],
|
||||
Name: processName,
|
||||
})
|
||||
if !seenPIDs[pid] {
|
||||
seenPIDs[pid] = true
|
||||
processes = append(processes, ProcessSystemInfo{
|
||||
PID: pid,
|
||||
Port: portInt,
|
||||
Proto: fields[0],
|
||||
Name: processName,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -156,19 +161,39 @@ func killProcessByName(name string) error {
|
|||
|
||||
switch osType {
|
||||
case "darwin", "linux":
|
||||
cmd = exec.Command("pkill", name)
|
||||
// 使用 pgrep 查找进程 PID
|
||||
pgrepCmd := exec.Command("pgrep", "-f", name)
|
||||
pgrepOutput, err := pgrepCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find process with name %s: %v", name, err)
|
||||
}
|
||||
|
||||
// 将输出转换为字符串并按行分割
|
||||
pids := strings.Split(strings.TrimSpace(string(pgrepOutput)), "\n")
|
||||
|
||||
// 对于每个找到的 PID,使用 kill 命令杀死进程
|
||||
for _, pidStr := range pids {
|
||||
pid, err := strconv.Atoi(pidStr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert PID to integer: %v", err)
|
||||
continue
|
||||
}
|
||||
// 每次循环使用新的 *exec.Cmd 实例
|
||||
killCmd := exec.Command("kill", "-9", strconv.Itoa(pid))
|
||||
if err := killCmd.Run(); err != nil {
|
||||
log.Printf("Failed to kill process with PID %d: %v", pid, err)
|
||||
}
|
||||
}
|
||||
case "windows":
|
||||
cmd = exec.Command("taskkill", "/IM", name, "/F") // /F 表示强制结束
|
||||
cmd = SetHideConsoleCursor(cmd)
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("Failed to kill process with name %s: %v", name, err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported operating system")
|
||||
}
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("Failed to kill process with name %s: %v", name, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,10 +150,10 @@ func GetStoreInfoByPath(infoPath string) (StoreInfo, error) {
|
|||
if err := json.Unmarshal(content, &storeInfo); err != nil {
|
||||
return storeInfo, fmt.Errorf("failed to unmarshal info.json: %v", err)
|
||||
}
|
||||
scriptPath := storeInfo.Setting.BinPath
|
||||
if !libs.PathExists(scriptPath) {
|
||||
return storeInfo, fmt.Errorf("script file '%s' not found", scriptPath)
|
||||
}
|
||||
// scriptPath := storeInfo.Setting.BinPath
|
||||
// if !libs.PathExists(scriptPath) {
|
||||
// return storeInfo, fmt.Errorf("script file '%s' not found", scriptPath)
|
||||
// }
|
||||
return storeInfo, nil
|
||||
}
|
||||
func GetInstalled() []InstallInfo {
|
||||
|
|
|
|||
Loading…
Reference in a new issue