添加demo
This commit is contained in:
parent
a92cc1f291
commit
d352d7608d
12 changed files with 141 additions and 36 deletions
|
|
@ -20,7 +20,7 @@
|
||||||
"name": "", // string, 应用程序名称。
|
"name": "", // string, 应用程序名称。
|
||||||
"url": "", // string, 应用程序下载地址。
|
"url": "", // string, 应用程序下载地址。
|
||||||
"webUrl":"", // string, 如何设置,应用程序将显示到桌面。
|
"webUrl":"", // string, 如何设置,应用程序将显示到桌面。
|
||||||
"isDev": true, // boolean, 是否为开发环境。
|
"isDev": true, // boolean, 是否为开发环境。如果设置为true将不会下载数据。
|
||||||
"needDownload": true, // boolean, 是否需要下载,本地开发设置为false。
|
"needDownload": true, // boolean, 是否需要下载,本地开发设置为false。
|
||||||
"needInstall": true, // boolean, 是否需要安装。
|
"needInstall": true, // boolean, 是否需要安装。
|
||||||
"version": "1.0.0", // string, 应用程序版本。
|
"version": "1.0.0", // string, 应用程序版本。
|
||||||
|
|
@ -73,9 +73,11 @@ type InstallInfo struct {
|
||||||
},
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"startEnvs": [],
|
"startEnvs": [],
|
||||||
|
"beforeCmds": [],// 启动前需要执行的命令列表。可调用命令列表集commands里面的命令。
|
||||||
"startCmds": [// object[], 纯参数命令集。将启动`setting.binPath`,不可调用命令列表集`commands`里面的命令。
|
"startCmds": [// object[], 纯参数命令集。将启动`setting.binPath`,不可调用命令列表集`commands`里面的命令。
|
||||||
"--defaults-file={exePath}/my.ini"
|
"--defaults-file={exePath}/my.ini"
|
||||||
]
|
],
|
||||||
|
"AfterCmds": []// 启动后需要执行的命令列表。可调用命令列表集commands里面的命令。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -114,7 +116,7 @@ type Cmd struct {
|
||||||
TplPath string `json:"tplPath,omitempty"` // 命令的模板路径。
|
TplPath string `json:"tplPath,omitempty"` // 命令的模板路径。
|
||||||
Cmds []string `json:"cmds,omitempty"` // 要执行的子命令列表。
|
Cmds []string `json:"cmds,omitempty"` // 要执行的子命令列表。
|
||||||
Waiting int `json:"waiting"` // 等待的时间。
|
Waiting int `json:"waiting"` // 等待的时间。
|
||||||
Kill bool `json:"kill"` // 标志位,表示是否需要终止之前的命令。如果setting中设置了progressName会优先杀死整个进程
|
Kill bool `json:"kill"` // 标志位,表示是否需要终止之前的命令。如果设置了`content`中的进程名,则优先以进程名字杀死进程
|
||||||
Envs []Item `json:"envs"` // 命令执行时的环境变量。
|
Envs []Item `json:"envs"` // 命令执行时的环境变量。
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -126,8 +128,10 @@ type InstallStruct struct {
|
||||||
InstallCmds []string `json:"installCmds"` // 安装过程中需要执行的命令列表。
|
InstallCmds []string `json:"installCmds"` // 安装过程中需要执行的命令列表。
|
||||||
}
|
}
|
||||||
type StartStruct struct {
|
type StartStruct struct {
|
||||||
StartEnvs []Item `json:"startEnvs"` // 安装过程中需要的环境变量。
|
StartEnvs []Item `json:"startEnvs"` // 启动过程中需要的环境变量。
|
||||||
StartCmds []string `json:"startCmds"` // 安装过程中需要执行的命令列表。
|
BeforeCmds []string `json:"beforeCmds"` // 启动前需要执行的命令列表。可调用命令列表集commands里面的命令。
|
||||||
|
StartCmds []string `json:"startCmds"` // 启动过程中需要执行的命令列表。
|
||||||
|
AfterCmds []string `json:"afterCmds"` // 启动后需要执行的命令列表。可调用命令列表集commands里面的命令。
|
||||||
}
|
}
|
||||||
// Item 是一个通用的键值对结构体,用于表示配置项或环境变量等。
|
// Item 是一个通用的键值对结构体,用于表示配置项或环境变量等。
|
||||||
type Item struct {
|
type Item struct {
|
||||||
|
|
@ -184,6 +188,7 @@ const comp = await fetch('http://localhost:56780/store/setting', {
|
||||||
"--init-file={exePath}/password.txt"
|
"--init-file={exePath}/password.txt"
|
||||||
],
|
],
|
||||||
"waiting": 3,
|
"waiting": 3,
|
||||||
|
"content": "mysqld.exe",
|
||||||
"kill": true
|
"kill": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -226,4 +231,7 @@ const comp = await fetch('http://localhost:56780/store/setting', {
|
||||||
11. `startApp` 启动其他应用,content为应用名
|
11. `startApp` 启动其他应用,content为应用名
|
||||||
12. `stopApp` 停止其他应用,content为应用名
|
12. `stopApp` 停止其他应用,content为应用名
|
||||||
|
|
||||||
|
### 进阶操作
|
||||||
|
1. 下载[mysql8.0](https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.39-winx64.zip)
|
||||||
|
2. 参考demo下的mysql8.0目录,尝试自己制作安装包
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "mysql5.7",
|
"name": "mysql5.7",
|
||||||
"url": "https://gitee.com/ruitao_admin/godoos-mysql5.7/releases/download/mysql5.7/mysql5.7.zip",
|
"url": "https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.44-winx64.zip",
|
||||||
"isDev": true,
|
"isDev": true,
|
||||||
"needDownload": true,
|
"needDownload": true,
|
||||||
"needInstall": true,
|
"needInstall": true,
|
||||||
"version": "5.7.37",
|
"version": "5.7.44",
|
||||||
"icon": "https://img0.baidu.com/it/u=1087008535,3349487719&fm=253&fmt=auto&app=138&f=PNG?w=969&h=500",
|
"icon": "https://img0.baidu.com/it/u=1087008535,3349487719&fm=253&fmt=auto&app=138&f=PNG?w=969&h=500",
|
||||||
"checkProgress": true,
|
"checkProgress": true,
|
||||||
"hasRestart": true,
|
"hasRestart": true,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
"name": "mysql5.7",
|
|
||||||
"icon": "mysql.png",
|
"icon": "mysql.png",
|
||||||
"setting": {
|
"setting": {
|
||||||
"binPath": "{exePath}/bin/mysqld.exe",
|
"binPath": "{exePath}/bin/mysqld.exe",
|
||||||
|
|
@ -32,6 +31,7 @@
|
||||||
"--init-file={exePath}/password.txt"
|
"--init-file={exePath}/password.txt"
|
||||||
],
|
],
|
||||||
"waiting": 3,
|
"waiting": 3,
|
||||||
|
"content": "mysqld.exe",
|
||||||
"kill": true
|
"kill": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
"--init-file={exePath}/password.txt"
|
"--init-file={exePath}/password.txt"
|
||||||
],
|
],
|
||||||
"waiting": 3,
|
"waiting": 3,
|
||||||
|
"content": "mysqld.exe",
|
||||||
"kill": true
|
"kill": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
13
docs/demo/mysql8.0/install.json
Normal file
13
docs/demo/mysql8.0/install.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "mysql8.0",
|
||||||
|
"url": "https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.39-winx64.zip",
|
||||||
|
"isDev": true,
|
||||||
|
"needDownload": true,
|
||||||
|
"needInstall": true,
|
||||||
|
"version": "8.0.39",
|
||||||
|
"icon": "https://img0.baidu.com/it/u=1087008535,3349487719&fm=253&fmt=auto&app=138&f=PNG?w=969&h=500",
|
||||||
|
"checkProgress": true,
|
||||||
|
"hasRestart": true,
|
||||||
|
"setting": true,
|
||||||
|
"isOn": true
|
||||||
|
}
|
||||||
29
docs/demo/mysql8.0/my.ini.tpl
Normal file
29
docs/demo/mysql8.0/my.ini.tpl
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
[client]
|
||||||
|
port = 3306
|
||||||
|
|
||||||
|
[mysql]
|
||||||
|
no-auto-rehash
|
||||||
|
default-character-set = utf8mb4
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
basedir = "{exePath}"
|
||||||
|
datadir = "{dataDir}"
|
||||||
|
port = {port}
|
||||||
|
server_id = 1
|
||||||
|
character-set-server = utf8mb4
|
||||||
|
|
||||||
|
default_authentication_plugin = mysql_native_password
|
||||||
|
|
||||||
|
explicit_defaults_for_timestamp = on
|
||||||
|
tls-version = ''
|
||||||
|
skip-mysqlx
|
||||||
|
|
||||||
|
table_open_cache = 256
|
||||||
|
|
||||||
|
log_timestamps = SYSTEM
|
||||||
|
|
||||||
|
log-error = "{logDir}/mysql.log"
|
||||||
|
|
||||||
|
[mysqldump]
|
||||||
|
quick
|
||||||
|
max_allowed_packet = 512M
|
||||||
12
docs/demo/redis5.0/install.json
Normal file
12
docs/demo/redis5.0/install.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "redis5.0",
|
||||||
|
"icon": "redis.png",
|
||||||
|
"setting": {
|
||||||
|
"binPath": "{exePath}/redis-server.exe"
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"startCmds": [
|
||||||
|
"{exePath}/redis.windows.conf"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,12 @@
|
||||||
import { ref, defineProps } from "vue";
|
import { ref, defineProps } from "vue";
|
||||||
import { OpenDirDialog } from "@/util/goutil";
|
import { OpenDirDialog } from "@/util/goutil";
|
||||||
import { getSystemKey, parseJson } from "@/system/config";
|
import { getSystemKey, parseJson } from "@/system/config";
|
||||||
const apiUrl = getSystemKey("apiUrl");
|
import { useStoreStore } from "@/stores/store";
|
||||||
import { notifySuccess, notifyError } from "@/util/msg";
|
import { notifySuccess, notifyError } from "@/util/msg";
|
||||||
import { t } from "@/i18n";
|
import { t } from "@/i18n";
|
||||||
|
const apiUrl = getSystemKey("apiUrl");
|
||||||
|
const store = useStoreStore()
|
||||||
|
const fileInput = ref()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
install: {
|
install: {
|
||||||
type: Function,
|
type: Function,
|
||||||
|
|
@ -22,10 +25,10 @@ const addType = [
|
||||||
'name': '远程下载',
|
'name': '远程下载',
|
||||||
'type': 'download'
|
'type': 'download'
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// 'name': '本地导入',
|
'name': '本地导入',
|
||||||
// 'type': 'local'
|
'type': 'local'
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
'name': '开发模式',
|
'name': '开发模式',
|
||||||
'type': 'dev'
|
'type': 'dev'
|
||||||
|
|
@ -76,7 +79,27 @@ async function addAppByDownload() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function addAppByImport() {
|
async function addAppByImport() {
|
||||||
|
fileInput.value.click()
|
||||||
|
}
|
||||||
|
async function upload(e: any) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('files', file);
|
||||||
|
const completion = await fetch(apiUrl + '/store/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
if (!completion.ok) {
|
||||||
|
notifyError(t("store.importError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const item = await completion.json()
|
||||||
|
//console.log(item)
|
||||||
|
if(item.data){
|
||||||
|
await installPlugin(item.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function addAppByDev() {
|
async function addAppByDev() {
|
||||||
if(formData.value.devPath && formData.value.devPath != ""){
|
if(formData.value.devPath && formData.value.devPath != ""){
|
||||||
|
|
@ -91,8 +114,9 @@ async function installPlugin(pluginName: string) {
|
||||||
}
|
}
|
||||||
const item = await completion.json()
|
const item = await completion.json()
|
||||||
//console.log(item)
|
//console.log(item)
|
||||||
item.isOut = true
|
item.data.isOut = true
|
||||||
await props.install(item.data)
|
await props.install(item.data)
|
||||||
|
store.changeCate(0, 'hots')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -112,7 +136,8 @@ async function installPlugin(pluginName: string) {
|
||||||
<el-button type="primary" @click="addAppByDownload()">添加</el-button>
|
<el-button type="primary" @click="addAppByDownload()">添加</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="formData.importType == 'local'">
|
<template v-if="formData.importType == 'local'">
|
||||||
<el-button type="primary" @click="addAppByImport()">导入</el-button>
|
<input type="file" style="display: none;" ref="fileInput" accept=".zip,.tar,.tar.gz,.tar.bz2" @change="upload">
|
||||||
|
<el-button type="primary" @click="addAppByImport()">导入压缩包</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="formData.importType == 'dev'">
|
<template v-if="formData.importType == 'dev'">
|
||||||
<el-form-item label="本地路径">
|
<el-form-item label="本地路径">
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,10 @@ function setCache() {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
async function install(item: any) {
|
async function install(item: any) {
|
||||||
|
//console.log(item)
|
||||||
if (item.isOut) {
|
if (item.isOut) {
|
||||||
item.progress = 0
|
item.progress = 0
|
||||||
const flag = store.addOutList(item)
|
const flag = await store.addOutList(item)
|
||||||
if(!flag){
|
if(!flag){
|
||||||
notifyError(t("store.installError"))
|
notifyError(t("store.installError"))
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +49,7 @@ async function install(item: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.webUrl) {
|
if (item.webUrl) {
|
||||||
sys.fs.writeFile(
|
await sys.fs.writeFile(
|
||||||
`${sys._options.userLocation}Desktop/${item.name}.url`,
|
`${sys._options.userLocation}Desktop/${item.name}.url`,
|
||||||
`link::url::${item.webUrl}::${item.icon}`
|
`link::url::${item.webUrl}::${item.icon}`
|
||||||
);
|
);
|
||||||
|
|
@ -61,6 +62,12 @@ async function install(item: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uninstall(item: any) {
|
async function uninstall(item: any) {
|
||||||
|
if (item.webUrl) {
|
||||||
|
await sys.fs.unlink(`${sys._options.userLocation}Desktop/${item.name}.url`);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete store.installedList[store.installedList.indexOf(item.name)];
|
||||||
|
setCache();
|
||||||
if (item.needInstall) {
|
if (item.needInstall) {
|
||||||
item.progress = 0
|
item.progress = 0
|
||||||
const completion = await fetch(store.apiUrl + '/store/uninstall?name=' + item.name)
|
const completion = await fetch(store.apiUrl + '/store/uninstall?name=' + item.name)
|
||||||
|
|
@ -74,10 +81,7 @@ async function uninstall(item: any) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys.fs.unlink(`${sys._options.userLocation}Desktop/${item.name}.url`);
|
|
||||||
notifySuccess(t("store.uninstallSuccess"))
|
notifySuccess(t("store.uninstallSuccess"))
|
||||||
delete store.installedList[store.installedList.indexOf(item.name)];
|
|
||||||
setCache();
|
|
||||||
}
|
}
|
||||||
async function download(item: any) {
|
async function download(item: any) {
|
||||||
//console.log(item)
|
//console.log(item)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ export const useStoreStore = defineStore('storeStore', () => {
|
||||||
}
|
}
|
||||||
let list:any = await res.json()
|
let list:any = await res.json()
|
||||||
//console.log(data)
|
//console.log(data)
|
||||||
if (outList.value.length > 0 && currentCate.value == 'hots') {
|
if (outList.value.length > 0 && currentCate.value == 'hots' && list && list.length > 0) {
|
||||||
const names = list.value.map((item : any) => item.name)
|
const names = list.map((item : any) => item.name)
|
||||||
const adds:any = []
|
const adds:any = []
|
||||||
outList.value.forEach((item : any) => {
|
outList.value.forEach((item : any) => {
|
||||||
if (!names.includes(item.name)) {
|
if (!names.includes(item.name)) {
|
||||||
|
|
@ -40,7 +40,9 @@ export const useStoreStore = defineStore('storeStore', () => {
|
||||||
isready.value = true;
|
isready.value = true;
|
||||||
}
|
}
|
||||||
async function addOutList(item:any) {
|
async function addOutList(item:any) {
|
||||||
|
console.log(item)
|
||||||
const has = outList.value.find((i:any) => i.name === item.name)
|
const has = outList.value.find((i:any) => i.name === item.name)
|
||||||
|
console.log(has)
|
||||||
if(!has) {
|
if(!has) {
|
||||||
item.isOut = true
|
item.isOut = true
|
||||||
outList.value.push(item)
|
outList.value.push(item)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,15 @@ func runStart(storeInfo StoreInfo) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set start environment variable %s: %w", storeInfo.Name, err)
|
return fmt.Errorf("failed to set start environment variable %s: %w", storeInfo.Name, err)
|
||||||
}
|
}
|
||||||
|
if len(storeInfo.Start.BeforeCmds) > 0 {
|
||||||
|
for _, cmdKey := range storeInfo.Start.BeforeCmds {
|
||||||
|
if _, ok := storeInfo.Commands[cmdKey]; ok {
|
||||||
|
// 如果命令存在,你可以进一步处理 cmds
|
||||||
|
RunCmds(storeInfo, cmdKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
binPath := storeInfo.Setting.BinPath
|
binPath := storeInfo.Setting.BinPath
|
||||||
if !libs.PathExists(binPath) {
|
if !libs.PathExists(binPath) {
|
||||||
return fmt.Errorf("script file %s does not exist", storeInfo.Setting.BinPath)
|
return fmt.Errorf("script file %s does not exist", storeInfo.Setting.BinPath)
|
||||||
|
|
@ -49,7 +58,15 @@ func runStart(storeInfo StoreInfo) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
}(cmd)
|
}(cmd)
|
||||||
|
if len(storeInfo.Start.AfterCmds) > 0 {
|
||||||
|
for _, cmdKey := range storeInfo.Start.AfterCmds {
|
||||||
|
if _, ok := storeInfo.Commands[cmdKey]; ok {
|
||||||
|
// 如果命令存在,你可以进一步处理 cmds
|
||||||
|
RunCmds(storeInfo, cmdKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func RunStartApp(appName string) error {
|
func RunStartApp(appName string) error {
|
||||||
|
|
@ -89,9 +106,9 @@ func runExec(storeInfo StoreInfo, cmdParam Cmd) error {
|
||||||
time.Sleep(time.Second * time.Duration(cmdParam.Waiting))
|
time.Sleep(time.Second * time.Duration(cmdParam.Waiting))
|
||||||
}
|
}
|
||||||
if cmdParam.Kill {
|
if cmdParam.Kill {
|
||||||
if storeInfo.Setting.ProgressName != "" {
|
if cmdParam.Content != "" {
|
||||||
if err := KillProcessByName(storeInfo.Setting.ProgressName); err != nil {
|
if err := KillProcessByName(cmdParam.Content); err != nil {
|
||||||
log.Printf("failed to kill process %s: %s", storeInfo.Setting.ProgressName, err.Error())
|
log.Printf("failed to kill process %s: %s", cmdParam.Content, err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := cmd.Process.Kill(); err != nil {
|
if err := cmd.Process.Kill(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package store
|
|
||||||
|
|
||||||
type ProcessInfo struct {
|
|
||||||
Port string
|
|
||||||
PingPath string // 增加ping或健康检查路径
|
|
||||||
}
|
|
||||||
|
|
||||||
var ProcessInfoMap = map[string]ProcessInfo{}
|
|
||||||
|
|
@ -65,6 +65,8 @@ type InstallStruct struct {
|
||||||
InstallCmds []string `json:"installCmds"` // 安装过程中需要执行的命令列表。
|
InstallCmds []string `json:"installCmds"` // 安装过程中需要执行的命令列表。
|
||||||
}
|
}
|
||||||
type StartStruct struct {
|
type StartStruct struct {
|
||||||
StartEnvs []Item `json:"startEnvs"` // 安装过程中需要的环境变量。
|
StartEnvs []Item `json:"startEnvs"` // 启动过程中需要的环境变量。
|
||||||
StartCmds []string `json:"startCmds"` // 安装过程中需要执行的命令列表。
|
BeforeCmds []string `json:"beforeCmds"` // 启动前需要执行的命令列表。
|
||||||
|
StartCmds []string `json:"startCmds"` // 启动过程中需要执行的命令列表。
|
||||||
|
AfterCmds []string `json:"afterCmds"` // 启动后需要执行的命令列表。
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue