@lazycatcloud/lzc-cli 1.1.8 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -11
- package/lib/api.js +71 -39
- package/lib/app/index.js +76 -21
- package/lib/app/lpk_build.js +95 -63
- package/lib/app/lpk_create.js +63 -41
- package/lib/app/lpk_create_generator.js +202 -0
- package/lib/app/lpk_devshell.js +393 -328
- package/lib/app/lpk_devshell_docker.js +211 -0
- package/lib/app/lpk_installer.js +63 -26
- package/lib/app/lpk_log.js +68 -0
- package/lib/app/lpk_status.js +18 -0
- package/lib/app/lpk_uninstall.js +19 -0
- package/lib/appstore/index.js +37 -0
- package/lib/appstore/login.js +96 -93
- package/lib/appstore/publish.js +62 -0
- package/lib/autologin.js +0 -78
- package/lib/box/api/clientapi.js +1322 -0
- package/lib/box/api/empty.js +35 -0
- package/lib/box/check_qemu.js +1 -0
- package/lib/box/index.js +41 -94
- package/lib/box/qemu_vm_mgr.js +208 -239
- package/lib/box/schemes/vm_box_system_debian.json +1 -1
- package/lib/docker-compose.js +1 -2
- package/lib/env.js +19 -101
- package/lib/key.js +1 -0
- package/lib/sdk.js +10 -25
- package/lib/utils.js +156 -132
- package/package.json +19 -10
- package/scripts/cli.js +14 -135
- package/template/_lpk/README.md +31 -0
- package/template/_lpk/exec.sh +19 -0
- package/template/_lpk/golang.manifest.yml.in +16 -0
- package/template/_lpk/lazycat.png +0 -0
- package/template/_lpk/lite.manifest.yml.in +19 -0
- package/template/_lpk/local_devshell/Dockerfile +16 -0
- package/template/_lpk/local_devshell/build.sh +5 -0
- package/template/_lpk/local_devshell/entrypoint.sh +87 -0
- package/template/{_lazycat/debug/shell → _lpk/local_devshell}/sshd_config +8 -8
- package/template/_lpk/manifest.yml.in +0 -1
- package/template/{vue/lzc-build.yml → _lpk/vue.lzc-build.yml.in} +9 -1
- package/template/golang/README.md +0 -2
- package/template/golang/_gitignore +2 -0
- package/template/golang/build.sh +6 -0
- package/template/golang/lazycat.png +0 -0
- package/template/golang/lzc-build.yml +9 -1
- package/template/golang/rego.go +15 -16
- package/template/golang/rego_test.go +13 -0
- package/template/ionic_vue3/lazycat.png +0 -0
- package/template/ionic_vue3/lzc-build.yml +9 -1
- package/template/lite/error_pages/502.html.tpl +13 -0
- package/template/lite/lazycat.png +0 -0
- package/template/lite/lzc-build.yml +60 -0
- package/cmds/app.js +0 -133
- package/cmds/config.js +0 -55
- package/cmds/create.js +0 -55
- package/cmds/dev.js +0 -130
- package/cmds/init.js +0 -125
- package/cmds/log.js +0 -103
- package/cmds/publish.js +0 -116
- package/lib/archiver.js +0 -105
- package/lib/box/hportal.js +0 -120
- package/lib/builder.js +0 -313
- package/lib/dev.js +0 -314
- package/lib/generator.js +0 -146
- package/template/_lazycat/_gitignore +0 -1
- package/template/_lazycat/app-config +0 -1
- package/template/_lazycat/debug/devforward/50x.html +0 -30
- package/template/_lazycat/debug/devforward/Dockerfile +0 -16
- package/template/_lazycat/debug/devforward/docker-compose.override.yml.in +0 -11
- package/template/_lazycat/debug/devforward/entrypoint.sh +0 -10
- package/template/_lazycat/debug/devforward/nginx.conf.template +0 -56
- package/template/_lazycat/debug/devforward/sshd_config +0 -116
- package/template/_lazycat/debug/shell/50x.html +0 -32
- package/template/_lazycat/debug/shell/Dockerfile +0 -18
- package/template/_lazycat/debug/shell/build.sh +0 -15
- package/template/_lazycat/debug/shell/docker-compose.override.yml.in +0 -13
- package/template/_lazycat/debug/shell/entrypoint.sh +0 -12
- package/template/_lazycat/docker-compose.yml.in +0 -15
- package/template/_lazycat/icon.svg +0 -1
- package/template/_lazycat/screenshot.png +0 -0
- package/template/_lpk/sync/Dockerfile +0 -16
- package/template/_lpk/sync/build.sh +0 -5
- package/template/_lpk/sync/entrypoint.sh +0 -8
- package/template/_lpk/sync/sshd_config +0 -117
- package/template/_lpk/sync.manifest.yml.in +0 -3
- package/template/release/golang/Dockerfile +0 -18
- package/template/release/golang/build.sh +0 -13
- package/template/release/ionic_vue3/Dockerfile +0 -10
- package/template/release/ionic_vue3/build.sh +0 -7
- package/template/release/ionic_vue3/docker-compose.yml.in +0 -3
- package/template/release/vue/Dockerfile +0 -10
- package/template/release/vue/build.sh +0 -10
- package/template/release/vue/docker-compose.yml.in +0 -3
- package/template/vue/README.md +0 -29
- package/template/vue/_dockerignore +0 -1
- package/template/vue/babel.config.js +0 -3
- package/template/vue/package.json +0 -43
- package/template/vue/public/favicon.ico +0 -0
- package/template/vue/public/index.html +0 -33
- package/template/vue/src/App.vue +0 -39
- package/template/vue/src/main.js +0 -8
- package/template/vue/src/todo.vue +0 -640
- package/template/vue/src/top-bar.vue +0 -100
- package/template/vue/src/webdav.vue +0 -183
- package/template/vue/vue.config.js +0 -21
package/README.md
CHANGED
|
@@ -1,21 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
# 懒猫云应用命令行工具
|
|
2
|
+
```
|
|
3
|
+
<command> [options]
|
|
4
|
+
|
|
5
|
+
Commands:
|
|
6
|
+
lzc-cli box 盒子管理 lzc-cli app 应用管理 lzc-cli project 项目管理 lzc-cli appstore 应用商店
|
|
7
|
+
Options:
|
|
8
|
+
-h, --help [boolean] [default: false]
|
|
9
|
+
--version Show version number [boolean]
|
|
10
|
+
--log log level 'trace', 'debug', 'info', 'warn', 'error'
|
|
11
|
+
[string] [default: "info"]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
```
|
|
16
|
+
npm install -g @lazycatcloud/lzc-cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 虚拟盒子
|
|
20
|
+
|
|
21
|
+
### 创建虚拟盒子
|
|
22
|
+
```
|
|
23
|
+
lzc-cli box create
|
|
24
|
+
```
|
|
25
|
+
将从 https://dl.lazycat.cloud 中下载最新的盒子系统数据,跟创建对应的 qemu 虚拟盒子。
|
|
26
|
+
|
|
27
|
+
### 启动盒子
|
|
28
|
+
```
|
|
29
|
+
lzc-cli box start <boxname>
|
|
30
|
+
# lzc-cli box start mydemobox
|
|
31
|
+
```
|
|
32
|
+
启动盒子成功后,就可以在 https://<mydemobox>.heiyu.space 中看到盒子的主页了。
|
|
33
|
+
|
|
34
|
+
### 切换默认的盒子
|
|
35
|
+
```
|
|
36
|
+
lzc-cli box switch <otherBoxName>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 查看本地的虚拟盒子信息
|
|
40
|
+
```
|
|
41
|
+
lzc-cli box info
|
|
42
|
+
```
|
|
2
43
|
|
|
3
|
-
|
|
44
|
+
## 应用管理
|
|
4
45
|
|
|
5
|
-
|
|
46
|
+
### 安装应用到盒子中去
|
|
6
47
|
|
|
7
|
-
|
|
8
|
-
|
|
48
|
+
- 从 https://repo.lazycat.cloud 中安装
|
|
49
|
+
```
|
|
50
|
+
lzc-cli app install https://repo.lazycat.cloud/pkgs/cloud.lazycat.app.kityminder/cloud.lazycat.app.kityminder-v1.0.3.lpk
|
|
9
51
|
```
|
|
10
52
|
|
|
11
|
-
|
|
53
|
+
- 从本地安装
|
|
54
|
+
```
|
|
55
|
+
lzc-cli app install ./kityminder.lpk
|
|
56
|
+
```
|
|
12
57
|
|
|
13
|
-
|
|
14
|
-
|
|
58
|
+
### 卸载应用
|
|
59
|
+
```
|
|
60
|
+
lzc-cli app uninstall cloud.lazycat.app.kityminder
|
|
15
61
|
```
|
|
16
62
|
|
|
17
|
-
|
|
63
|
+
## 项目管理
|
|
18
64
|
|
|
19
|
-
|
|
20
|
-
|
|
65
|
+
### 初始化懒猫云应用
|
|
66
|
+
```
|
|
67
|
+
lzc-cli project create yourappname
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 构建 lpk 包
|
|
71
|
+
```
|
|
72
|
+
lzc-cli project build -o yourappname.lpk
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 盒子内开发
|
|
76
|
+
```
|
|
77
|
+
lzc-cli project devshell -b
|
|
21
78
|
```
|
|
79
|
+
`-b` 表示是否重新构建盒子中项目环境。
|
package/lib/api.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import ora from "ora";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import fs from "fs";
|
|
4
|
-
import
|
|
4
|
+
import logger from "loglevel";
|
|
5
|
+
import fetch from "node-fetch";
|
|
5
6
|
|
|
6
7
|
//
|
|
7
8
|
// sdk 提供的API
|
|
@@ -10,10 +11,12 @@ export default class API {
|
|
|
10
11
|
this.appId = appId;
|
|
11
12
|
this.host = host;
|
|
12
13
|
}
|
|
13
|
-
async
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
async install(zipPath) {
|
|
15
|
+
if (!fs.existsSync(zipPath)) {
|
|
16
|
+
throw `${zipPath} 不存在`;
|
|
17
|
+
}
|
|
18
|
+
const resp = await fetch(
|
|
19
|
+
`${this.host}/api/v1/app/install?id=${this.appId}`,
|
|
17
20
|
{
|
|
18
21
|
method: "POST",
|
|
19
22
|
body: fs.createReadStream(zipPath),
|
|
@@ -22,36 +25,65 @@ export default class API {
|
|
|
22
25
|
if (resp.status != 200) {
|
|
23
26
|
throw chalk.red(await resp.text());
|
|
24
27
|
}
|
|
25
|
-
// update
|
|
26
28
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
|
|
30
|
+
async uninstall() {
|
|
31
|
+
return await fetch(`${this.host}/api/v1/app/uninstall?id=${this.appId}`, {
|
|
32
|
+
method: "DELETE",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async resume() {
|
|
37
|
+
const resp = await fetch(
|
|
38
|
+
`${this.host}/api/v1/app/resume?id=${this.appId}`,
|
|
36
39
|
{
|
|
37
40
|
method: "POST",
|
|
38
|
-
body: fs.createReadStream(zipPath),
|
|
39
41
|
}
|
|
40
42
|
);
|
|
41
43
|
if (resp.status != 200) {
|
|
42
|
-
|
|
44
|
+
const text = await resp.text();
|
|
45
|
+
throw text;
|
|
43
46
|
}
|
|
44
|
-
// update
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
async
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
async hasMount() {
|
|
50
|
+
const resp = await fetch(
|
|
51
|
+
`${this.host}/api/v1/app/hasMount?id=${this.appId}`,
|
|
52
|
+
{
|
|
53
|
+
method: "GET",
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
if (resp.status == 200) {
|
|
57
|
+
return true;
|
|
58
|
+
} else {
|
|
59
|
+
const text = await resp.text();
|
|
60
|
+
if (text) {
|
|
61
|
+
logger.debug("hasMount request failed", text);
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async isDevshell() {
|
|
68
|
+
const resp = await fetch(
|
|
69
|
+
`${this.host}/api/v1/app/isDevshell?id=${this.appId}`,
|
|
70
|
+
{
|
|
71
|
+
method: "GET",
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
if (resp.status == 200) {
|
|
75
|
+
return true;
|
|
76
|
+
} else {
|
|
77
|
+
const text = await resp.text();
|
|
78
|
+
if (text) {
|
|
79
|
+
logger.debug("isDevshell request failed", text);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
51
83
|
}
|
|
52
84
|
|
|
53
85
|
async status() {
|
|
54
|
-
const resp = await
|
|
86
|
+
const resp = await fetch(`${this.host}/api/v1/app/status?id=${this.appId}`);
|
|
55
87
|
if (resp.status == 200) {
|
|
56
88
|
const status = await resp.json();
|
|
57
89
|
return status;
|
|
@@ -63,7 +95,7 @@ export default class API {
|
|
|
63
95
|
}
|
|
64
96
|
|
|
65
97
|
async postPublicKey(key) {
|
|
66
|
-
const resp = await
|
|
98
|
+
const resp = await fetch(`${this.host}/api/v1/register`, {
|
|
67
99
|
method: "POST",
|
|
68
100
|
body: key,
|
|
69
101
|
});
|
|
@@ -72,7 +104,7 @@ export default class API {
|
|
|
72
104
|
}
|
|
73
105
|
}
|
|
74
106
|
|
|
75
|
-
async checkStatus() {
|
|
107
|
+
async checkStatus(resume = false) {
|
|
76
108
|
const spinner = ora().start();
|
|
77
109
|
let { status, info } = await this.status();
|
|
78
110
|
spinner.text = "部署进度 " + status;
|
|
@@ -83,12 +115,17 @@ export default class API {
|
|
|
83
115
|
break;
|
|
84
116
|
case "error":
|
|
85
117
|
spinner.stop();
|
|
86
|
-
|
|
118
|
+
logger.error("应用状态错误,请在盒子中查看对应的错误信息");
|
|
87
119
|
throw info?.msg;
|
|
88
120
|
default:
|
|
89
121
|
try {
|
|
90
|
-
await desireStatusTimer((result) => {
|
|
122
|
+
await desireStatusTimer(async (result) => {
|
|
91
123
|
spinner.text = "部署进度 " + result.status;
|
|
124
|
+
|
|
125
|
+
if (result.status == "paused" && resume) {
|
|
126
|
+
await this.resume();
|
|
127
|
+
}
|
|
128
|
+
|
|
92
129
|
return result.status === "running";
|
|
93
130
|
}, this.status.bind(this));
|
|
94
131
|
} catch (error) {
|
|
@@ -103,33 +140,28 @@ export default class API {
|
|
|
103
140
|
}
|
|
104
141
|
|
|
105
142
|
export function desireStatusTimer(desireCheckFn, getStatusFn) {
|
|
106
|
-
|
|
143
|
+
let errorCount = 0;
|
|
107
144
|
return new Promise((resolve, reject) => {
|
|
108
145
|
function schedule(timeout) {
|
|
109
146
|
setTimeout(async () => {
|
|
147
|
+
const answer = await getStatusFn();
|
|
110
148
|
try {
|
|
111
|
-
const answer = await getStatusFn();
|
|
112
149
|
if (answer) {
|
|
113
150
|
if (answer.status == "error") {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
reject(new Error(answer.error));
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
schedule(timeout);
|
|
120
|
-
} else if (desireCheckFn(answer)) {
|
|
151
|
+
throw new Error(answer.error);
|
|
152
|
+
} else if (await desireCheckFn(answer)) {
|
|
121
153
|
resolve(answer);
|
|
122
154
|
} else {
|
|
123
155
|
schedule(1000);
|
|
124
156
|
}
|
|
125
157
|
}
|
|
126
158
|
} catch (e) {
|
|
127
|
-
|
|
128
|
-
if (
|
|
159
|
+
errorCount += 1;
|
|
160
|
+
if (errorCount >= 3) {
|
|
129
161
|
reject(e);
|
|
130
162
|
return;
|
|
131
163
|
}
|
|
132
|
-
schedule(
|
|
164
|
+
schedule(1000);
|
|
133
165
|
}
|
|
134
166
|
}, timeout);
|
|
135
167
|
}
|
package/lib/app/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import lpkCreate
|
|
2
|
+
import lpkCreate from "./lpk_create.js";
|
|
3
3
|
import { LpkBuild } from "./lpk_build.js";
|
|
4
|
-
import { AppDevShell } from "./lpk_devshell.js";
|
|
4
|
+
import { AppDevShell, fallbackToRsync } from "./lpk_devshell.js";
|
|
5
5
|
import { LpkInstaller } from "./lpk_installer.js";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import { LpkUninstaller } from "./lpk_uninstall.js";
|
|
7
|
+
import { LpkStatuser } from "./lpk_status.js";
|
|
8
|
+
import { LpkLogger } from "./lpk_log.js";
|
|
8
9
|
|
|
9
10
|
export function lpkProjectCommand(program) {
|
|
10
11
|
let subCommands = [
|
|
@@ -12,7 +13,7 @@ export function lpkProjectCommand(program) {
|
|
|
12
13
|
command: "create <name>",
|
|
13
14
|
desc: "创建懒猫云应用",
|
|
14
15
|
handler: async ({ name }) => {
|
|
15
|
-
await lpkCreate(
|
|
16
|
+
await lpkCreate(name);
|
|
16
17
|
},
|
|
17
18
|
},
|
|
18
19
|
{
|
|
@@ -24,10 +25,14 @@ export function lpkProjectCommand(program) {
|
|
|
24
25
|
describe: "输出文件",
|
|
25
26
|
type: "string",
|
|
26
27
|
});
|
|
28
|
+
args.option("f", {
|
|
29
|
+
alias: "file",
|
|
30
|
+
describe: "指定构建的lzc-build.yml文件",
|
|
31
|
+
type: "string",
|
|
32
|
+
});
|
|
27
33
|
},
|
|
28
|
-
handler: async ({ context, output }) => {
|
|
29
|
-
const lpk = new LpkBuild();
|
|
30
|
-
await lpk.init();
|
|
34
|
+
handler: async ({ context, output, file }) => {
|
|
35
|
+
const lpk = await new LpkBuild(context, file).init();
|
|
31
36
|
// 正常的打包逻辑不需要 devshell
|
|
32
37
|
lpk.onBeforeBuildPackage(async (options) => {
|
|
33
38
|
delete options["devshell"];
|
|
@@ -44,20 +49,35 @@ export function lpkProjectCommand(program) {
|
|
|
44
49
|
command: "devshell [context]",
|
|
45
50
|
desc: "进入盒子的开发环境",
|
|
46
51
|
builder: (args) => {
|
|
47
|
-
args.option("
|
|
48
|
-
alias: "
|
|
49
|
-
|
|
52
|
+
args.option("r", {
|
|
53
|
+
alias: "rsync",
|
|
54
|
+
deprecate: true,
|
|
55
|
+
type: "boolean",
|
|
56
|
+
default: fallbackToRsync(),
|
|
57
|
+
});
|
|
58
|
+
const shell = process.env.SHELL
|
|
59
|
+
? path.basename(process.env.SHELL)
|
|
60
|
+
: "sh";
|
|
61
|
+
args.option("s", {
|
|
62
|
+
alias: "shell",
|
|
63
|
+
describe: "指定你最喜欢的shell",
|
|
64
|
+
type: "string",
|
|
65
|
+
default: shell,
|
|
66
|
+
});
|
|
67
|
+
args.option("f", {
|
|
68
|
+
alias: "force",
|
|
69
|
+
describe: "强制重新构建",
|
|
50
70
|
type: "boolean",
|
|
51
|
-
default: false,
|
|
52
71
|
});
|
|
53
72
|
},
|
|
54
|
-
handler: async ({ context,
|
|
55
|
-
const app = new AppDevShell(context);
|
|
73
|
+
handler: async ({ context, shell, rsync, force }) => {
|
|
74
|
+
const app = new AppDevShell(context, undefined, rsync, force);
|
|
56
75
|
await app.init();
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
await app.build();
|
|
77
|
+
if (rsync) {
|
|
78
|
+
await app.rsyncShell(shell);
|
|
59
79
|
} else {
|
|
60
|
-
await app.shell
|
|
80
|
+
await app.sshfsShell(shell);
|
|
61
81
|
}
|
|
62
82
|
},
|
|
63
83
|
},
|
|
@@ -74,12 +94,47 @@ export function lpkProjectCommand(program) {
|
|
|
74
94
|
export function lpkAppCommand(program) {
|
|
75
95
|
let subCommands = [
|
|
76
96
|
{
|
|
77
|
-
command: "install <
|
|
78
|
-
desc: "
|
|
79
|
-
handler: async ({
|
|
97
|
+
command: "install <pkgUrl>",
|
|
98
|
+
desc: "部署应用至设备, pkgUrl 可以为路径,或者https://,http://请求地址",
|
|
99
|
+
handler: async ({ pkgUrl }) => {
|
|
80
100
|
const installer = new LpkInstaller();
|
|
81
101
|
await installer.init();
|
|
82
|
-
await installer.install(
|
|
102
|
+
await installer.install(pkgUrl);
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
command: "uninstall <pkgId>",
|
|
107
|
+
desc: "从设备中卸载某一个应用",
|
|
108
|
+
handler: async ({ pkgId }) => {
|
|
109
|
+
const uninstaller = new LpkUninstaller();
|
|
110
|
+
await uninstaller.init();
|
|
111
|
+
await uninstaller.uninstall(pkgId);
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
command: "status <pkgId>",
|
|
116
|
+
desc: "获取某一个应用的状态",
|
|
117
|
+
handler: async ({ pkgId }) => {
|
|
118
|
+
const statuser = new LpkStatuser();
|
|
119
|
+
await statuser.init();
|
|
120
|
+
await statuser.status(pkgId);
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
command: "log <pkgId>",
|
|
125
|
+
desc: "查看某一个app的日志",
|
|
126
|
+
builder: (args) => {
|
|
127
|
+
args.option("f", {
|
|
128
|
+
alias: "follow",
|
|
129
|
+
describe: "持续输出",
|
|
130
|
+
type: "boolean",
|
|
131
|
+
default: false,
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
handler: async ({ pkgId, follow }) => {
|
|
135
|
+
const log = new LpkLogger();
|
|
136
|
+
await log.init();
|
|
137
|
+
await log.start(pkgId, follow);
|
|
83
138
|
},
|
|
84
139
|
},
|
|
85
140
|
];
|
package/lib/app/lpk_build.js
CHANGED
|
@@ -87,11 +87,35 @@ async function fetchIconTo(options, cwd, destDir) {
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// 提供一些方便的环境变量,可以在 lzc-build.yml 中直接使用
|
|
91
|
+
// - LocalIP 本地局域网ip
|
|
92
|
+
function localIp() {
|
|
93
|
+
const output = spawnSync("ip", ["route", "get", "1.1.1.1"], {
|
|
94
|
+
encoding: "utf-8",
|
|
95
|
+
});
|
|
96
|
+
const match = output.stdout.match(/src\ (.+)\ uid/i);
|
|
97
|
+
if (match) {
|
|
98
|
+
return match[1];
|
|
99
|
+
} else {
|
|
100
|
+
logger.debug("get LocalIP environment error", output.stderr);
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function convenientEnv() {
|
|
105
|
+
return Object.assign(
|
|
106
|
+
{},
|
|
107
|
+
{
|
|
108
|
+
LocalIP: localIp(),
|
|
109
|
+
},
|
|
110
|
+
process.env
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
90
114
|
export class LpkBuild {
|
|
91
|
-
constructor(cwd) {
|
|
115
|
+
constructor(cwd, lzcBuild = "lzc-build.yml") {
|
|
92
116
|
this.pwd = cwd ?? process.cwd();
|
|
93
117
|
|
|
94
|
-
this.optionsFilePath = path.join(this.pwd,
|
|
118
|
+
this.optionsFilePath = path.join(this.pwd, lzcBuild);
|
|
95
119
|
this.options = loadFromYaml(this.optionsFilePath);
|
|
96
120
|
|
|
97
121
|
this.manifestFilePath = this.options["manifest"]
|
|
@@ -108,9 +132,14 @@ export class LpkBuild {
|
|
|
108
132
|
// init 时替换 lzc-build.yml 中的模板字段
|
|
109
133
|
async init() {
|
|
110
134
|
const manifest = await this.getManifest();
|
|
135
|
+
const primitive = convenientEnv();
|
|
111
136
|
this.options = yaml.load(
|
|
112
|
-
await envTemplateFile(
|
|
137
|
+
await envTemplateFile(
|
|
138
|
+
this.optionsFilePath,
|
|
139
|
+
Object.assign({}, primitive, manifest)
|
|
140
|
+
)
|
|
113
141
|
);
|
|
142
|
+
return this;
|
|
114
143
|
}
|
|
115
144
|
|
|
116
145
|
// onBeforeDumpYaml
|
|
@@ -119,7 +148,7 @@ export class LpkBuild {
|
|
|
119
148
|
this.beforeDumpYamlFn.push(fn);
|
|
120
149
|
}
|
|
121
150
|
// onBeforeTarContent
|
|
122
|
-
// fn: function(contentdir) => void
|
|
151
|
+
// fn: function(contentdir, options) => void
|
|
123
152
|
onBeforeTarContent(fn) {
|
|
124
153
|
this.beforeTarContentFn.push(fn);
|
|
125
154
|
}
|
|
@@ -146,7 +175,7 @@ export class LpkBuild {
|
|
|
146
175
|
return this.manifest;
|
|
147
176
|
}
|
|
148
177
|
|
|
149
|
-
async exec(
|
|
178
|
+
async exec() {
|
|
150
179
|
if (this.beforeBuildPackageFn.length > 0) {
|
|
151
180
|
this.options = await this.beforeBuildPackageFn.reduce(
|
|
152
181
|
async (prev, curr) => {
|
|
@@ -168,74 +197,77 @@ export class LpkBuild {
|
|
|
168
197
|
logger.warn("跳过执行 buildscript");
|
|
169
198
|
}
|
|
170
199
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
throw `${pkgout} 不存在`;
|
|
177
|
-
}
|
|
200
|
+
// 输出路径
|
|
201
|
+
let packName = this.options["lpkPath"];
|
|
202
|
+
const pkgout = path.resolve(this.pwd, this.options["pkgout"]);
|
|
203
|
+
if (!packName && !isDirExist(pkgout)) {
|
|
204
|
+
throw `${pkgout} 不存在`;
|
|
178
205
|
}
|
|
179
206
|
|
|
180
207
|
const tempDir = fs.mkdtempSync(".lzc-cli-build");
|
|
181
|
-
|
|
182
208
|
let contentdir = this.options["contentdir"];
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
209
|
+
try {
|
|
210
|
+
if (contentdir) {
|
|
211
|
+
contentdir = path.resolve(this.pwd, contentdir);
|
|
212
|
+
if (!isDirExist(contentdir)) {
|
|
213
|
+
throw `${contentdir} 不存在`;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
logger.warn("跳过拷贝 contentdir 内容");
|
|
217
|
+
// 当没有指定的 contentdir 的时候,也生成一个空的文件夹
|
|
218
|
+
// 原因是:可能其他地方会复制内容进来,像 devshell 中的会在打包的时候,将ssh key拷贝进来
|
|
219
|
+
contentdir = fs.mkdtempSync(path.join(tempDir, "fake-contentdir"));
|
|
189
220
|
}
|
|
190
|
-
} else {
|
|
191
|
-
logger.warn("跳过拷贝 contentdir 内容");
|
|
192
|
-
// 当没有指定的 contentdir 的时候,也生成一个空的文件夹
|
|
193
|
-
// 原因是:可能其他地方会复制内容进来,像 devshell 中的会在打包的时候,将ssh key拷贝进来
|
|
194
|
-
contentdir = fs.mkdtempSync(path.join(tempDir, "fake-contentdir"));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// 开始打包 contentdir
|
|
198
|
-
if (this.beforeTarContentFn.length > 0) {
|
|
199
|
-
await this.beforeTarContentFn.reduce(async (prev, curr) => {
|
|
200
|
-
let _prev = await prev;
|
|
201
|
-
await curr(_prev);
|
|
202
|
-
return _prev;
|
|
203
|
-
}, contentdir);
|
|
204
|
-
}
|
|
205
|
-
tarContentDir("./", path.join(tempDir, "content.tar"), contentdir);
|
|
206
221
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
logger.debug("manifest\n", manifest);
|
|
218
|
-
dumpToYaml(manifest, path.join(tempDir, "manifest.yml"));
|
|
219
|
-
|
|
220
|
-
// 打包 lpk
|
|
221
|
-
if (this.beforeDumpLpkFn.length > 0) {
|
|
222
|
-
await this.beforeDumpLpkFn.reduce(async (prev, curr) => {
|
|
223
|
-
await curr(this.options, this.pwd, tempDir);
|
|
224
|
-
return prev;
|
|
225
|
-
}, {});
|
|
226
|
-
}
|
|
222
|
+
// 开始打包 contentdir
|
|
223
|
+
if (this.beforeTarContentFn.length > 0) {
|
|
224
|
+
await this.beforeTarContentFn.reduce(async (prev, curr) => {
|
|
225
|
+
let _prev = await prev;
|
|
226
|
+
await curr(_prev, this.options);
|
|
227
|
+
return _prev;
|
|
228
|
+
}, contentdir);
|
|
229
|
+
}
|
|
230
|
+
tarContentDir("./", path.join(tempDir, "content.tar"), contentdir);
|
|
227
231
|
|
|
232
|
+
// 如果是临时的 contentdir, 目录在打包完成后删除
|
|
233
|
+
if (!this.options["contentdir"]) {
|
|
234
|
+
fs.rmSync(contentdir, { recursive: true });
|
|
235
|
+
}
|
|
228
236
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
// 开始生成 manifest.yml
|
|
238
|
+
let manifest = await this.getManifest();
|
|
239
|
+
if (process.env.LZC_VERSION) {
|
|
240
|
+
manifest.version = process.env.LZC_VERSION;
|
|
241
|
+
}
|
|
242
|
+
if (this.beforeDumpYamlFn.length > 0) {
|
|
243
|
+
manifest = await this.beforeDumpYamlFn.reduce(async (prev, curr) => {
|
|
244
|
+
return await curr(await prev, this.options);
|
|
245
|
+
}, manifest);
|
|
246
|
+
}
|
|
247
|
+
logger.debug("manifest\n", manifest);
|
|
248
|
+
dumpToYaml(manifest, path.join(tempDir, "manifest.yml"));
|
|
249
|
+
|
|
250
|
+
// 打包 lpk
|
|
251
|
+
if (this.beforeDumpLpkFn.length > 0) {
|
|
252
|
+
await this.beforeDumpLpkFn.reduce(async (prev, curr) => {
|
|
253
|
+
await curr(this.options, this.pwd, tempDir);
|
|
254
|
+
return prev;
|
|
255
|
+
}, {});
|
|
256
|
+
}
|
|
232
257
|
|
|
233
|
-
|
|
234
|
-
|
|
258
|
+
if (!packName) {
|
|
259
|
+
packName = path.resolve(
|
|
260
|
+
pkgout,
|
|
261
|
+
`${manifest.package}-v${manifest.version}.lpk`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
235
264
|
|
|
236
|
-
|
|
237
|
-
|
|
265
|
+
const lpkPath = await archiveFolderTo(tempDir, packName);
|
|
266
|
+
logger.info(`输出lpk包 ${lpkPath.path}`);
|
|
238
267
|
|
|
239
|
-
|
|
268
|
+
return lpkPath.path;
|
|
269
|
+
} finally {
|
|
270
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
271
|
+
}
|
|
240
272
|
}
|
|
241
273
|
}
|