@lazycatcloud/lzc-cli 1.1.13 → 1.2.1

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.
Files changed (40) hide show
  1. package/README.md +30 -62
  2. package/lib/app/index.js +33 -35
  3. package/lib/app/lpk_debug_bridge.js +101 -0
  4. package/lib/app/lpk_devshell.js +55 -114
  5. package/lib/app/lpk_installer.js +43 -40
  6. package/lib/appstore/login.js +1 -1
  7. package/lib/appstore/publish.js +18 -8
  8. package/lib/box/index.js +2 -86
  9. package/lib/env.js +18 -178
  10. package/lib/lzc_sdk.js +16 -2
  11. package/lib/shellapi.js +95 -0
  12. package/lib/shellapi.proto +301 -0
  13. package/lib/utils.js +2 -103
  14. package/package.json +4 -26
  15. package/template/_lpk/busybox-1.35.0 +0 -0
  16. package/template/_lpk/exec.sh +1 -10
  17. package/template/_lpk/init_debug_bridge.sh +24 -0
  18. package/template/_lpk/vue.lzc-build.yml.in +0 -16
  19. package/template/golang/lzc-build.yml +0 -15
  20. package/template/ionic_vue3/lzc-build.yml +0 -16
  21. package/template/ionic_vue3/package-lock.json +8100 -0
  22. package/template/lite/lzc-build.yml +0 -28
  23. package/lib/api.js +0 -155
  24. package/lib/app/lpk_devshell_docker.js +0 -211
  25. package/lib/app/lpk_log.js +0 -68
  26. package/lib/app/lpk_status.js +0 -18
  27. package/lib/app/lpk_uninstall.js +0 -19
  28. package/lib/box/api/clientapi.js +0 -1322
  29. package/lib/box/api/empty.js +0 -35
  30. package/lib/box/check_qemu.js +0 -51
  31. package/lib/box/qemu_vm_mgr.js +0 -608
  32. package/lib/box/schemes/vm_box_system_debian.json +0 -47
  33. package/lib/core.proto +0 -118
  34. package/lib/docker/promise.js +0 -91
  35. package/lib/docker-compose.js +0 -50
  36. package/lib/fetch.js +0 -50
  37. package/lib/git/git-commit.sh +0 -7
  38. package/lib/git/git-reset.sh +0 -15
  39. package/lib/key.js +0 -102
  40. package/lib/sdk.js +0 -135
package/README.md CHANGED
@@ -1,79 +1,47 @@
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
- ```
1
+ # lzc-cli 指南
13
2
 
14
- ## 安装
15
- ```
16
- npm install -g @lazycatcloud/lzc-cli
17
- ```
3
+ #### 依赖
18
4
 
19
- ## 虚拟盒子
5
+ 1. `ssh`
6
+ 2. `ssh-copy-id`
7
+ 3. `rsync`
20
8
 
21
- ### 创建虚拟盒子
22
- ```
23
- lzc-cli box create
24
- ```
25
- 将从 https://dl.lazycat.cloud 中下载最新的盒子系统数据,跟创建对应的 qemu 虚拟盒子。
9
+ #### 快速上手
26
10
 
27
- ### 启动盒子
28
- ```
29
- lzc-cli box start <boxname>
30
- # lzc-cli box start mydemobox
11
+ ```bash
12
+ npm install -g @lazycatcloud/lzc-cli
13
+ # 将 lzc-cli 添加 bash/zsh 补全支持
14
+ lzc-cli completion >> ~/.zshrc
31
15
  ```
32
- 启动盒子成功后,就可以在 https://<mydemobox>.heiyu.space 中看到盒子的主页了。
33
16
 
34
- ### 切换默认的盒子
35
- ```
36
- lzc-cli box switch <otherBoxName>
37
- ```
17
+ 下面开始使用 `lzc-cli` 去创建一个项目吧!
38
18
 
39
- ### 查看本地的虚拟盒子信息
40
- ```
41
- lzc-cli box info
42
- ```
19
+ ```bash
20
+ lzc-cli project create you_project
43
21
 
44
- ## 应用管理
22
+ # 构建懒猫云平台lpk包
23
+ lzc-cli project build
45
24
 
46
- ### 安装应用到盒子中去
25
+ # 将lpk包安装到盒子中去
26
+ lzc-cli app install
47
27
 
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
51
- ```
28
+ # 使用 devshell 可以让你在盒子中开发调试
29
+ lzc-cli project devshell
52
30
 
53
- - 从本地安装
54
- ```
55
- lzc-cli app install ./kityminder.lpk
31
+ # 经过测试后,将包发布到懒猫云商店中去
32
+ lzc-cli appstore publish
56
33
  ```
57
34
 
58
- ### 卸载应用
59
- ```
60
- lzc-cli app uninstall cloud.lazycat.app.kityminder
61
- ```
35
+ ### FAQ
62
36
 
63
- ## 项目管理
37
+ #### 1. 开发者工具 ssh 的帐号密码是多少?
64
38
 
65
- ### 初始化懒猫云应用
66
- ```
67
- lzc-cli project create yourappname
68
- ```
39
+ 现在帐号密码设置为 box:box,后面会使用 pam 模块对接盒子帐号体系。
69
40
 
70
- ### 构建 lpk 包
71
- ```
72
- lzc-cli project build -o yourappname.lpk
73
- ```
41
+ #### 2. 如何切换默认的开发的盒子?
74
42
 
75
- ### 盒子内开发
76
- ```
77
- lzc-cli project devshell -b
78
- ```
79
- `-b` 表示是否重新构建盒子中项目环境。
43
+ 目前不支持通过 lzc-cli 工具切换默认的盒子,所以你需要在 lzc-client-desktop 客户端上点击你要使用的盒子来切换。
44
+
45
+ #### 3. 如果在盒子中构建镜像? 不想在本地构建
46
+
47
+ 现在已经把在盒子中构建镜像的功能去掉了,只能在本地或者其他地方构建好,然后指定 image 字段来选择你需要的开发环境。
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 fetch from "../fetch.js";
11
- import { sdkEnv } from "../env.js";
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, shell, force, config, contentdir }) => {
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 app.rsyncShell(shell);
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 <pkgUrl>",
118
- desc: "部署应用至设备, pkgUrl 可以为路径,或者https://,http://请求地址",
119
- handler: async ({ pkgUrl }) => {
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(pkgUrl);
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
- const uninstaller = new LpkUninstaller();
130
- await uninstaller.init();
131
- await uninstaller.uninstall(pkgId);
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
- const statuser = new LpkStatuser();
139
- await statuser.init();
140
- await statuser.status(pkgId);
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 ({ pkgId, follow }) => {
155
- const log = new LpkLogger();
156
- await log.init();
157
- await log.start(pkgId, follow);
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
+ }
@@ -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
- function sdkSSHHost() {
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, uid = "") {
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() || (await this.notRunning()) || (await this.noDevshell())
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
- const depsStr = deps.sort().join(" ");
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
- const tag = `${manifest["package"]}-devshell:${manifest["version"]}`;
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(runShell) {
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(pairs["private"], pkgId, runShell, uid);
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(keyFile, appId, runShell = "sh", uid = "") {
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(keyFile, appId) {
414
- const host = sdkSSHHost();
415
- const port = sdkSSHPort();
360
+ async syncProject(appId) {
416
361
  // prettier-ignore
417
362
  let rsh = [
418
363
  "ssh",
419
- "-p", `${port}`,
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
- let rsyncDebug = process.env.RSYNCDEBUG ? "-P" : "";
435
- const userId = this.uid ? `/${this.uid}` : "";
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 . ${host}:${storePath} --filter=':- .gitignore' --ignore-errors --usermap=:nobody --groupmap=*:nobody`,
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(keyFile, appId) {
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(keyFile, appId);
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(keyFile, this.appId);
456
+ await this.syncProject(this.appId);
515
457
  // 注册watch函数
516
- await this.watchFile(keyFile, this.appId);
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 sdk = new SdkDocker();
528
- await sdk.interactiveShell(this.appId, this.runShell, this.uid);
468
+ const bridge = new DebugBridge();
469
+ await bridge.devshell(this.appId);
529
470
  }
530
471
  }