@lazycatcloud/lzc-cli 1.1.13 → 1.2.0
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/lib/app/index.js +33 -35
- package/lib/app/lpk_debug_bridge.js +101 -0
- package/lib/app/lpk_devshell.js +55 -114
- package/lib/app/lpk_installer.js +43 -40
- package/lib/appstore/login.js +1 -1
- package/lib/appstore/publish.js +18 -8
- package/lib/box/index.js +2 -86
- package/lib/env.js +18 -178
- package/lib/lzc_sdk.js +16 -2
- package/lib/shellapi.js +95 -0
- package/lib/shellapi.proto +301 -0
- package/lib/utils.js +2 -103
- package/package.json +3 -24
- package/template/_lpk/busybox-1.35.0 +0 -0
- package/template/_lpk/exec.sh +1 -10
- package/template/_lpk/init_debug_bridge.sh +24 -0
- package/template/_lpk/vue.lzc-build.yml.in +0 -16
- package/template/golang/lzc-build.yml +0 -15
- package/template/ionic_vue3/lzc-build.yml +0 -16
- package/template/ionic_vue3/package-lock.json +8100 -0
- package/template/lite/lzc-build.yml +0 -28
- package/lib/api.js +0 -155
- package/lib/app/lpk_devshell_docker.js +0 -211
- package/lib/app/lpk_log.js +0 -68
- package/lib/app/lpk_status.js +0 -18
- package/lib/app/lpk_uninstall.js +0 -19
- package/lib/box/api/clientapi.js +0 -1322
- package/lib/box/api/empty.js +0 -35
- package/lib/box/check_qemu.js +0 -51
- package/lib/box/qemu_vm_mgr.js +0 -608
- package/lib/box/schemes/vm_box_system_debian.json +0 -47
- package/lib/core.proto +0 -118
- package/lib/docker/promise.js +0 -91
- package/lib/docker-compose.js +0 -50
- package/lib/fetch.js +0 -50
- package/lib/git/git-commit.sh +0 -7
- package/lib/git/git-reset.sh +0 -15
- package/lib/key.js +0 -102
- package/lib/sdk.js +0 -135
package/lib/app/index.js
CHANGED
|
@@ -3,12 +3,10 @@ import lpkCreate from "./lpk_create.js";
|
|
|
3
3
|
import { LpkBuild } from "./lpk_build.js";
|
|
4
4
|
import { AppDevShell } from "./lpk_devshell.js";
|
|
5
5
|
import { LpkInstaller } from "./lpk_installer.js";
|
|
6
|
-
import { LpkUninstaller } from "./lpk_uninstall.js";
|
|
7
|
-
import { LpkStatuser } from "./lpk_status.js";
|
|
8
|
-
import { LpkLogger } from "./lpk_log.js";
|
|
9
6
|
import logger from "loglevel";
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
7
|
+
import { sleep } from "../utils.js";
|
|
8
|
+
import { DebugBridge } from "./lpk_debug_bridge.js";
|
|
9
|
+
import shellApi from "../shellapi.js";
|
|
12
10
|
|
|
13
11
|
export function lpkProjectCommand(program) {
|
|
14
12
|
let subCommands = [
|
|
@@ -16,6 +14,8 @@ export function lpkProjectCommand(program) {
|
|
|
16
14
|
command: "create <name>",
|
|
17
15
|
desc: "创建懒猫云应用",
|
|
18
16
|
handler: async ({ name }) => {
|
|
17
|
+
await shellApi.init();
|
|
18
|
+
|
|
19
19
|
await lpkCreate(name);
|
|
20
20
|
},
|
|
21
21
|
},
|
|
@@ -35,6 +35,8 @@ export function lpkProjectCommand(program) {
|
|
|
35
35
|
});
|
|
36
36
|
},
|
|
37
37
|
handler: async ({ context, output, file }) => {
|
|
38
|
+
await shellApi.init();
|
|
39
|
+
|
|
38
40
|
const lpk = await new LpkBuild(context, file).init();
|
|
39
41
|
// 正常的打包逻辑不需要 devshell
|
|
40
42
|
lpk.onBeforeBuildPackage(async (options) => {
|
|
@@ -52,18 +54,6 @@ export function lpkProjectCommand(program) {
|
|
|
52
54
|
command: "devshell [context]",
|
|
53
55
|
desc: "进入盒子的开发环境",
|
|
54
56
|
builder: (args) => {
|
|
55
|
-
args.option("r", {
|
|
56
|
-
alias: "rsync",
|
|
57
|
-
deprecate: true,
|
|
58
|
-
type: "boolean",
|
|
59
|
-
default: true,
|
|
60
|
-
});
|
|
61
|
-
args.option("s", {
|
|
62
|
-
alias: "shell",
|
|
63
|
-
describe: "指定你最喜欢的shell",
|
|
64
|
-
type: "string",
|
|
65
|
-
default: "bash",
|
|
66
|
-
});
|
|
67
57
|
args.option("f", {
|
|
68
58
|
alias: "force",
|
|
69
59
|
describe: "强制重新构建",
|
|
@@ -80,7 +70,9 @@ export function lpkProjectCommand(program) {
|
|
|
80
70
|
type: "boolean",
|
|
81
71
|
});
|
|
82
72
|
},
|
|
83
|
-
handler: async ({ context,
|
|
73
|
+
handler: async ({ context, force, config, contentdir }) => {
|
|
74
|
+
await shellApi.init();
|
|
75
|
+
|
|
84
76
|
const cwd = context ? path.resolve(context) : process.cwd();
|
|
85
77
|
const lpkBuild = await new LpkBuild(cwd, config).init();
|
|
86
78
|
lpkBuild.onBeforeBuildPackage(async (options) => {
|
|
@@ -94,11 +86,11 @@ export function lpkProjectCommand(program) {
|
|
|
94
86
|
}
|
|
95
87
|
return options;
|
|
96
88
|
});
|
|
97
|
-
await fetch(`${sdkEnv.sdkUrl}/api/v1/ping`);
|
|
98
89
|
const app = new AppDevShell(cwd, lpkBuild, force);
|
|
99
90
|
await app.init();
|
|
100
91
|
await app.build();
|
|
101
|
-
await
|
|
92
|
+
await sleep(2000);
|
|
93
|
+
await app.rsyncShell();
|
|
102
94
|
},
|
|
103
95
|
},
|
|
104
96
|
];
|
|
@@ -114,30 +106,36 @@ export function lpkProjectCommand(program) {
|
|
|
114
106
|
export function lpkAppCommand(program) {
|
|
115
107
|
let subCommands = [
|
|
116
108
|
{
|
|
117
|
-
command: "install
|
|
118
|
-
desc: "部署应用至设备,
|
|
119
|
-
handler: async ({
|
|
109
|
+
command: "install [pkgPath]",
|
|
110
|
+
desc: "部署应用至设备, pkgPath 可以为路径,或者https://,http://请求地址, 如果不填写,将默认为当前目录下的lpk",
|
|
111
|
+
handler: async ({ pkgPath }) => {
|
|
112
|
+
await shellApi.init();
|
|
113
|
+
|
|
114
|
+
pkgPath = pkgPath ?? process.cwd();
|
|
120
115
|
const installer = new LpkInstaller();
|
|
121
116
|
await installer.init();
|
|
122
|
-
await installer.install(
|
|
117
|
+
await installer.install(pkgPath);
|
|
123
118
|
},
|
|
124
119
|
},
|
|
125
120
|
{
|
|
126
121
|
command: "uninstall <pkgId>",
|
|
127
122
|
desc: "从设备中卸载某一个应用",
|
|
128
123
|
handler: async ({ pkgId }) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
await shellApi.init();
|
|
125
|
+
|
|
126
|
+
const bridge = new DebugBridge();
|
|
127
|
+
await bridge.uninstall(pkgId);
|
|
132
128
|
},
|
|
133
129
|
},
|
|
134
130
|
{
|
|
135
131
|
command: "status <pkgId>",
|
|
136
132
|
desc: "获取某一个应用的状态",
|
|
137
133
|
handler: async ({ pkgId }) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
await shellApi.init();
|
|
135
|
+
|
|
136
|
+
const bridge = new DebugBridge();
|
|
137
|
+
const status = await bridge.status(pkgId);
|
|
138
|
+
console.log(status);
|
|
141
139
|
},
|
|
142
140
|
},
|
|
143
141
|
{
|
|
@@ -151,17 +149,17 @@ export function lpkAppCommand(program) {
|
|
|
151
149
|
default: false,
|
|
152
150
|
});
|
|
153
151
|
},
|
|
154
|
-
handler: async (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
handler: async () => {
|
|
153
|
+
await shellApi.init();
|
|
154
|
+
|
|
155
|
+
throw "还没有实现";
|
|
158
156
|
},
|
|
159
157
|
},
|
|
160
158
|
];
|
|
161
159
|
program.command({
|
|
162
160
|
command: "app",
|
|
163
161
|
desc: "应用管理",
|
|
164
|
-
builder: (args) => {
|
|
162
|
+
builder: async (args) => {
|
|
165
163
|
args.command(subCommands);
|
|
166
164
|
},
|
|
167
165
|
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import shellApi from "../shellapi.js";
|
|
4
|
+
import inquirer from "inquirer";
|
|
5
|
+
|
|
6
|
+
export class DebugBridge {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.uid = shellApi.uid;
|
|
9
|
+
this.boxname = shellApi.boxname;
|
|
10
|
+
this.sshCmd = `ssh -p 22222 box@dev.${this.boxname}.heiyu.space`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
common(cmd, args) {
|
|
14
|
+
const ssh = spawnSync(cmd, args, {
|
|
15
|
+
shell: true,
|
|
16
|
+
encoding: "utf-8",
|
|
17
|
+
stdio: "pipe",
|
|
18
|
+
});
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
ssh.status == 0 ? resolve(ssh.stdout) : reject(ssh.stderr);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async install(lpkPath) {
|
|
25
|
+
if (!(await this.canPublicKey())) {
|
|
26
|
+
await this.sshCopyId();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const stream = fs.createReadStream(lpkPath);
|
|
30
|
+
const ssh = spawn(this.sshCmd, [`install --uid ${this.uid}`], {
|
|
31
|
+
shell: true,
|
|
32
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
33
|
+
});
|
|
34
|
+
stream.pipe(ssh.stdin);
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
ssh.on("close", (code) => {
|
|
37
|
+
code == 0 ? resolve() : reject("install 失败");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async canPublicKey() {
|
|
43
|
+
try {
|
|
44
|
+
await this.common(this.sshCmd, [`-o PasswordAuthentication=no`]);
|
|
45
|
+
return true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async sshCopyId() {
|
|
52
|
+
const questions = [
|
|
53
|
+
{
|
|
54
|
+
name: "upload",
|
|
55
|
+
type: "input",
|
|
56
|
+
default: "y",
|
|
57
|
+
message:
|
|
58
|
+
"检测到你目前使用的密码帐号登录,是否使用 ssh-copy-id 上传密钥 (y/n): ",
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
const answers = await inquirer.prompt(questions);
|
|
62
|
+
if (answers.upload.toLowerCase() == "y") {
|
|
63
|
+
return this.common(`ssh-copy-id`, [
|
|
64
|
+
`-f -p 22222 box@dev.${this.boxname}.heiyu.space`,
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async status(appId) {
|
|
70
|
+
return this.common(this.sshCmd, [`status --uid ${this.uid}`, appId]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async isDevshell(appId) {
|
|
74
|
+
const stdout = await this.common(this.sshCmd, [`isDevshell`, appId]);
|
|
75
|
+
return stdout == "true";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async resume(appId) {
|
|
79
|
+
return this.common(this.sshCmd, [`resume --uid ${this.uid}`, appId]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async uninstall(appId) {
|
|
83
|
+
return this.common(this.sshCmd, [`uninstall --uid ${this.uid}`, appId]);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async devshell(appId) {
|
|
87
|
+
const stream = spawn(
|
|
88
|
+
this.sshCmd,
|
|
89
|
+
["-t", "devshell", appId, "/lzcapp/pkg/content/devshell/exec.sh"],
|
|
90
|
+
{
|
|
91
|
+
shell: true,
|
|
92
|
+
stdio: "inherit",
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
stream.on("close", (code) => {
|
|
97
|
+
code == 0 ? resolve() : reject();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
package/lib/app/lpk_devshell.js
CHANGED
|
@@ -3,7 +3,6 @@ import path from "node:path";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import logger from "loglevel";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
|
-
import { LpkBuild } from "./lpk_build.js";
|
|
7
6
|
import { LpkInstaller } from "./lpk_installer.js";
|
|
8
7
|
import debounce from "lodash.debounce";
|
|
9
8
|
import {
|
|
@@ -12,32 +11,18 @@ import {
|
|
|
12
11
|
ensureDir,
|
|
13
12
|
isFileExist,
|
|
14
13
|
GitIgnore,
|
|
15
|
-
sleep,
|
|
16
14
|
md5String,
|
|
17
15
|
md5File,
|
|
18
|
-
createTemplateFileCommon,
|
|
19
16
|
loadFromYaml,
|
|
20
17
|
FileLocker,
|
|
21
18
|
} from "../utils.js";
|
|
22
|
-
import Key from "../key.js";
|
|
23
19
|
import os from "node:os";
|
|
24
|
-
import { sdkEnv } from "../env.js";
|
|
25
20
|
import commandExists from "command-exists";
|
|
26
21
|
import chokidar from "chokidar";
|
|
27
22
|
import _ from "lodash";
|
|
28
|
-
import BoxAPI from "../api.js";
|
|
29
|
-
import { SdkDocker } from "./lpk_devshell_docker.js";
|
|
30
23
|
import { getUidByManifest } from "../lzc_sdk.js";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const sdkUrl = sdkEnv.sdkUrl;
|
|
34
|
-
let url = new URL(sdkUrl);
|
|
35
|
-
return `box@${url.hostname}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function sdkSSHPort() {
|
|
39
|
-
return 2222;
|
|
40
|
-
}
|
|
24
|
+
import { DebugBridge } from "./lpk_debug_bridge.js";
|
|
25
|
+
import shellApi from "../shellapi.js";
|
|
41
26
|
|
|
42
27
|
// 判断是否需要重新构建
|
|
43
28
|
// - 先判断 lzc-build.yml 是否发生改变
|
|
@@ -46,11 +31,9 @@ function sdkSSHPort() {
|
|
|
46
31
|
// - 根据 backend api 判断一个 appid 是否属于 running
|
|
47
32
|
// - 根据在 backend api 中判断同步的目录下是否存在文件 判断当前运行的 app 是否已经有一个挂载的实例,避免重复挂载
|
|
48
33
|
class AppDevShellMonitor {
|
|
49
|
-
constructor(cwd, pkgId
|
|
34
|
+
constructor(cwd, pkgId) {
|
|
50
35
|
this.pwd = cwd ? path.resolve(cwd) : process.cwd();
|
|
51
|
-
|
|
52
36
|
this.pkgId = pkgId;
|
|
53
|
-
this.boxapi = new BoxAPI(pkgId, sdkEnv.sdkUrl, uid);
|
|
54
37
|
|
|
55
38
|
this.optionsFilePath = path.join(this.pwd, "lzc-build.yml");
|
|
56
39
|
this.options = loadFromYaml(this.optionsFilePath);
|
|
@@ -66,6 +49,7 @@ class AppDevShellMonitor {
|
|
|
66
49
|
this.cacheFilePath = undefined;
|
|
67
50
|
this.oldHash = undefined;
|
|
68
51
|
this.newHash = undefined;
|
|
52
|
+
this.bridge = new DebugBridge();
|
|
69
53
|
}
|
|
70
54
|
|
|
71
55
|
async init() {
|
|
@@ -85,7 +69,9 @@ class AppDevShellMonitor {
|
|
|
85
69
|
|
|
86
70
|
async shouldBuild() {
|
|
87
71
|
return (
|
|
88
|
-
this.change() ||
|
|
72
|
+
this.change() ||
|
|
73
|
+
(await this.bridge.status(this.pkgId)) === "NotInstalled" ||
|
|
74
|
+
!(await this.bridge.isDevshell(this.pkgId))
|
|
89
75
|
);
|
|
90
76
|
}
|
|
91
77
|
|
|
@@ -113,19 +99,6 @@ class AppDevShellMonitor {
|
|
|
113
99
|
fs.writeFileSync(this.cacheFilePath, JSON.stringify(this.newHash));
|
|
114
100
|
}
|
|
115
101
|
}
|
|
116
|
-
|
|
117
|
-
async notRunning() {
|
|
118
|
-
try {
|
|
119
|
-
const { status } = await this.boxapi.status();
|
|
120
|
-
return status !== "running";
|
|
121
|
-
} catch {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async noDevshell() {
|
|
127
|
-
return !(await this.boxapi.isDevshell());
|
|
128
|
-
}
|
|
129
102
|
}
|
|
130
103
|
|
|
131
104
|
export class AppDevShell {
|
|
@@ -155,11 +128,6 @@ export class AppDevShell {
|
|
|
155
128
|
}
|
|
156
129
|
|
|
157
130
|
async devshellBuild() {
|
|
158
|
-
// 确保 sdk key ,并上传到 sdk
|
|
159
|
-
const k = new Key();
|
|
160
|
-
await k.ensure(sdkEnv.sdkUrl);
|
|
161
|
-
const pairs = await k.getKeyPair();
|
|
162
|
-
|
|
163
131
|
this.lpkBuild.onBeforeBuildPackage(async (options) => {
|
|
164
132
|
const devshell = options["devshell"];
|
|
165
133
|
if (!devshell) {
|
|
@@ -174,6 +142,30 @@ export class AppDevShell {
|
|
|
174
142
|
return options;
|
|
175
143
|
});
|
|
176
144
|
|
|
145
|
+
// 复制 busybox 到 devshell 中去
|
|
146
|
+
this.lpkBuild.onBeforeTarContent(async (contentdir) => {
|
|
147
|
+
const busyboxPath = path.join(
|
|
148
|
+
contextDirname(import.meta.url),
|
|
149
|
+
"../../template/_lpk/busybox-1.35.0"
|
|
150
|
+
);
|
|
151
|
+
let dest = path.join(contentdir, "devshell", "busybox");
|
|
152
|
+
ensureDir(dest);
|
|
153
|
+
fs.copyFileSync(busyboxPath, dest);
|
|
154
|
+
fs.chmodSync(dest, 0o775);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// 复制 init_debug_bridge.sh 到 devshell 中去
|
|
158
|
+
this.lpkBuild.onBeforeTarContent(async (contentdir) => {
|
|
159
|
+
const initPath = path.join(
|
|
160
|
+
contextDirname(import.meta.url),
|
|
161
|
+
"../../template/_lpk/init_debug_bridge.sh"
|
|
162
|
+
);
|
|
163
|
+
let dest = path.join(contentdir, "devshell", "init_debug_bridge.sh");
|
|
164
|
+
ensureDir(dest);
|
|
165
|
+
fs.copyFileSync(initPath, dest);
|
|
166
|
+
fs.chmodSync(dest, 0o775);
|
|
167
|
+
});
|
|
168
|
+
|
|
177
169
|
// 复制 exec.sh 到 devshell 中去
|
|
178
170
|
this.lpkBuild.onBeforeTarContent(async (contentdir) => {
|
|
179
171
|
const execScriptPath = path.join(
|
|
@@ -186,15 +178,6 @@ export class AppDevShell {
|
|
|
186
178
|
fs.chmodSync(dest, 0o775);
|
|
187
179
|
});
|
|
188
180
|
|
|
189
|
-
// 用 sdk ssh key 并复制到 contentdir 目录
|
|
190
|
-
// docker 中 sshd 的配置中已改成 /lzcapp/pkg/content/devshell/authorized_keys
|
|
191
|
-
this.lpkBuild.onBeforeTarContent(async (contentdir) => {
|
|
192
|
-
let publicKey = pairs["public"];
|
|
193
|
-
let dest = path.join(contentdir, "devshell", "authorized_keys");
|
|
194
|
-
ensureDir(dest);
|
|
195
|
-
fs.copyFileSync(publicKey, dest);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
181
|
// 复制 setupscript 脚本
|
|
199
182
|
this.lpkBuild.onBeforeTarContent(async (contentdir, options) => {
|
|
200
183
|
const devshell = options["devshell"];
|
|
@@ -227,6 +210,13 @@ export class AppDevShell {
|
|
|
227
210
|
const routes = devshell["routes"];
|
|
228
211
|
logger.debug("options devshell delete 'routes' field");
|
|
229
212
|
delete options["devshell"]["routes"];
|
|
213
|
+
|
|
214
|
+
// 添加 devshell 必要路由
|
|
215
|
+
routes.push(
|
|
216
|
+
"/__debug.bridge=exec://22222,/lzcapp/pkg/content/devshell/init_debug_bridge.sh"
|
|
217
|
+
);
|
|
218
|
+
routes.push("/__isdevshell=file:///lzcapp/pkg/devshell");
|
|
219
|
+
|
|
230
220
|
// 如果 devshell 中的 router 和 manifest 中的 prefix 出现冲突
|
|
231
221
|
// 优先使用 devshell 中的。
|
|
232
222
|
routes.forEach((r) => {
|
|
@@ -274,32 +264,7 @@ export class AppDevShell {
|
|
|
274
264
|
return manifest;
|
|
275
265
|
}
|
|
276
266
|
|
|
277
|
-
|
|
278
|
-
logger.debug("开始创建 Dockerfile 文件");
|
|
279
|
-
const tag = `${await md5String(depsStr)}:latest`;
|
|
280
|
-
|
|
281
|
-
const tempDir = fs.mkdtempSync(".lzc-cli-build-dependencies");
|
|
282
|
-
try {
|
|
283
|
-
const dockerfilePath = path.join(
|
|
284
|
-
contextDirname(import.meta.url),
|
|
285
|
-
"../../template/_lpk/Dockerfile.in"
|
|
286
|
-
);
|
|
287
|
-
await createTemplateFileCommon(
|
|
288
|
-
dockerfilePath,
|
|
289
|
-
path.join(tempDir, "Dockerfile"),
|
|
290
|
-
{ dependencies: depsStr }
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
logger.debug(`开始在盒子中构建 ${tag} 镜像 from ${tempDir}`);
|
|
294
|
-
const sdk = new SdkDocker();
|
|
295
|
-
await sdk.buildImage(tag, tempDir, tempDir);
|
|
296
|
-
} finally {
|
|
297
|
-
fs.rmSync(tempDir, { recursive: true });
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
delete manifest["application"]["devshell"];
|
|
301
|
-
manifest["application"]["image"] = tag;
|
|
302
|
-
return manifest;
|
|
267
|
+
throw "lzc-cli 不支持在盒子中构建 docker 镜像,请从其他地方构建,然后指定image字段";
|
|
303
268
|
});
|
|
304
269
|
|
|
305
270
|
// 如果 services 中有 devshell 的字段,需要检测是否需要提前构建
|
|
@@ -314,16 +279,7 @@ export class AppDevShell {
|
|
|
314
279
|
return manifest;
|
|
315
280
|
}
|
|
316
281
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
logger.debug(`开始在盒子中构建 ${tag} 镜像`);
|
|
320
|
-
|
|
321
|
-
const sdk = new SdkDocker();
|
|
322
|
-
await sdk.buildImage(tag, config["build"], process.cwd());
|
|
323
|
-
|
|
324
|
-
delete manifest["application"]["devshell"];
|
|
325
|
-
manifest["application"]["image"] = tag;
|
|
326
|
-
return manifest;
|
|
282
|
+
throw "lzc-cli 不支持在盒子中构建 docker 镜像,请从其他地方构建,然后指定image字段";
|
|
327
283
|
});
|
|
328
284
|
|
|
329
285
|
// 如果 devshell 中指定了 image 字段将使用 image 字段
|
|
@@ -361,13 +317,9 @@ export class AppDevShell {
|
|
|
361
317
|
let installer = new LpkInstaller();
|
|
362
318
|
await installer.init();
|
|
363
319
|
await installer.deploy(this.lpkBuild, true);
|
|
364
|
-
|
|
365
|
-
await sleep(2000);
|
|
366
320
|
}
|
|
367
321
|
|
|
368
|
-
async rsyncShell(
|
|
369
|
-
const k = new Key();
|
|
370
|
-
const pairs = await k.getKeyPair();
|
|
322
|
+
async rsyncShell() {
|
|
371
323
|
const manifest = await this.lpkBuild.getManifest();
|
|
372
324
|
const pkgId = manifest["package"];
|
|
373
325
|
|
|
@@ -386,7 +338,7 @@ export class AppDevShell {
|
|
|
386
338
|
}
|
|
387
339
|
|
|
388
340
|
const uid = await getUidByManifest(manifest);
|
|
389
|
-
const devshell = new DevShell(
|
|
341
|
+
const devshell = new DevShell(pkgId, uid);
|
|
390
342
|
if (isSync) {
|
|
391
343
|
await devshell.shell();
|
|
392
344
|
} else {
|
|
@@ -400,29 +352,22 @@ export class AppDevShell {
|
|
|
400
352
|
}
|
|
401
353
|
|
|
402
354
|
class DevShell {
|
|
403
|
-
constructor(
|
|
404
|
-
logger.debug("keyFile", keyFile);
|
|
405
|
-
logger.debug("appid", appId);
|
|
406
|
-
|
|
407
|
-
this.keyFile = keyFile;
|
|
355
|
+
constructor(appId, uid = "") {
|
|
408
356
|
this.appId = appId;
|
|
409
357
|
this.uid = uid;
|
|
410
|
-
this.runShell = runShell;
|
|
411
358
|
}
|
|
412
359
|
|
|
413
|
-
async syncProject(
|
|
414
|
-
const host = sdkSSHHost();
|
|
415
|
-
const port = sdkSSHPort();
|
|
360
|
+
async syncProject(appId) {
|
|
416
361
|
// prettier-ignore
|
|
417
362
|
let rsh = [
|
|
418
363
|
"ssh",
|
|
419
|
-
"-
|
|
364
|
+
"-J", `box@dev.${shellApi.boxname}.heiyu.space:22222`,
|
|
365
|
+
"-p", `22222`,
|
|
420
366
|
"-o", `"StrictHostKeyChecking=no"`,
|
|
421
367
|
"-o", `"UserKnownHostsFile=/dev/null"`,
|
|
422
368
|
"-o", `"ConnectionAttempts=3"`,
|
|
423
369
|
"-o", `"ConnectTimeout=30"`,
|
|
424
370
|
"-o", `"LogLevel=ERROR"`,
|
|
425
|
-
"-i", keyFile,
|
|
426
371
|
].join(" ");
|
|
427
372
|
// 检查rsync工具是否存在:提示用户
|
|
428
373
|
const rsyncExisted = commandExists.sync("rsync");
|
|
@@ -431,13 +376,11 @@ class DevShell {
|
|
|
431
376
|
process.exit(1);
|
|
432
377
|
}
|
|
433
378
|
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
let storePath = `/lzcsys/run/data/app/cache/${appId}${userId}/devshell`;
|
|
437
|
-
// FIXME: 下方执行命令不确定是否有兼容性问题
|
|
379
|
+
const rsyncDebug = process.env.RSYNCDEBUG ? "-P" : "";
|
|
380
|
+
const dest = `root@app.${appId}.lzcapp:/lzcapp/cache/devshell`;
|
|
438
381
|
try {
|
|
439
382
|
execSync(
|
|
440
|
-
`rsync ${rsyncDebug} --rsh='${rsh}' --recursive --relative --perms --update
|
|
383
|
+
`rsync ${rsyncDebug} --rsh='${rsh}' --recursive --relative --perms --update --filter=':- .gitignore' --ignore-errors --usermap=:nobody --groupmap=*:nobody . ${dest}`,
|
|
441
384
|
{ stdio: ["ignore", "inherit", "inherit"] }
|
|
442
385
|
);
|
|
443
386
|
} catch (err) {
|
|
@@ -487,7 +430,7 @@ class DevShell {
|
|
|
487
430
|
|
|
488
431
|
// 监听非.gitignore文件
|
|
489
432
|
// TODO: 目前仅仅监听process.cwd()以下的文件
|
|
490
|
-
async watchFile(
|
|
433
|
+
async watchFile(appId) {
|
|
491
434
|
const ignore = new GitIgnore(process.cwd());
|
|
492
435
|
await ignore.collect();
|
|
493
436
|
chokidar
|
|
@@ -502,29 +445,27 @@ class DevShell {
|
|
|
502
445
|
.on(
|
|
503
446
|
"all",
|
|
504
447
|
debounce(() => {
|
|
505
|
-
this.syncProject(
|
|
448
|
+
this.syncProject(appId);
|
|
506
449
|
}),
|
|
507
450
|
1000
|
|
508
451
|
);
|
|
509
452
|
}
|
|
510
453
|
async shell() {
|
|
511
|
-
let keyFile = this.keyFile;
|
|
512
454
|
try {
|
|
513
455
|
// 当进入shell的时候,都同步一次
|
|
514
|
-
await this.syncProject(
|
|
456
|
+
await this.syncProject(this.appId);
|
|
515
457
|
// 注册watch函数
|
|
516
|
-
await this.watchFile(
|
|
458
|
+
await this.watchFile(this.appId);
|
|
517
459
|
|
|
518
460
|
await this.connectShell();
|
|
519
461
|
} catch (e) {
|
|
520
462
|
console.log(e);
|
|
521
|
-
// this.reset();
|
|
522
463
|
return Promise.reject(e);
|
|
523
464
|
}
|
|
524
465
|
}
|
|
525
466
|
|
|
526
467
|
async connectShell() {
|
|
527
|
-
const
|
|
528
|
-
await
|
|
468
|
+
const bridge = new DebugBridge();
|
|
469
|
+
await bridge.devshell(this.appId);
|
|
529
470
|
}
|
|
530
471
|
}
|