@lazycatcloud/lzc-cli 1.2.27 → 1.2.28

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 (37) hide show
  1. package/lib/app/apkshell.js +37 -0
  2. package/lib/app/index.js +74 -74
  3. package/lib/app/lpk_build.js +113 -117
  4. package/lib/app/lpk_create.js +78 -148
  5. package/lib/app/lpk_create_generator.js +101 -74
  6. package/lib/app/lpk_debug_bridge.js +65 -62
  7. package/lib/app/lpk_devshell.js +227 -228
  8. package/lib/app/lpk_devshell_docker.js +28 -28
  9. package/lib/app/lpk_installer.js +59 -49
  10. package/lib/appstore/index.js +29 -29
  11. package/lib/appstore/login.js +64 -64
  12. package/lib/appstore/prePublish.js +68 -68
  13. package/lib/appstore/publish.js +55 -55
  14. package/lib/box/index.js +25 -25
  15. package/lib/env.js +18 -18
  16. package/lib/shellapi.js +55 -58
  17. package/lib/utils.js +217 -164
  18. package/package.json +7 -1
  19. package/scripts/cli.js +56 -56
  20. package/template/_lpk/manifest.yml.in +8 -8
  21. package/template/vue/README.md +29 -0
  22. package/template/vue/index.html +13 -0
  23. package/template/vue/lzc-build.yml +59 -0
  24. package/template/vue/lzc-icon.png +0 -0
  25. package/template/vue/package.json +20 -0
  26. package/template/vue/public/vite.svg +1 -0
  27. package/template/vue/src/App.vue +30 -0
  28. package/template/vue/src/assets/vue.svg +1 -0
  29. package/template/vue/src/components/HelloWorld.vue +41 -0
  30. package/template/vue/src/main.ts +5 -0
  31. package/template/vue/src/style.css +79 -0
  32. package/template/vue/src/vite-env.d.ts +1 -0
  33. package/template/vue/tsconfig.app.json +24 -0
  34. package/template/vue/tsconfig.json +7 -0
  35. package/template/vue/tsconfig.node.json +22 -0
  36. package/template/vue/vite.config.ts +7 -0
  37. package/template/ionic_vue3/package-lock.json +0 -8100
@@ -1,10 +1,10 @@
1
1
  // lzc-cli app devshell
2
- import path from "node:path";
3
- import fs from "node:fs";
4
- import logger from "loglevel";
5
- import { execSync } from "node:child_process";
6
- import { LpkInstaller } from "./lpk_installer.js";
7
- import debounce from "lodash.debounce";
2
+ import path from "node:path"
3
+ import fs from "node:fs"
4
+ import logger from "loglevel"
5
+ import { execSync } from "node:child_process"
6
+ import { LpkInstaller } from "./lpk_installer.js"
7
+ import debounce from "lodash.debounce"
8
8
  import {
9
9
  mergeYamlInMemory,
10
10
  contextDirname,
@@ -19,14 +19,14 @@ import {
19
19
  createTemplateFileCommon,
20
20
  isDebugMode,
21
21
  resolveDomain
22
- } from "../utils.js";
23
- import os from "node:os";
24
- import commandExists from "command-exists";
25
- import chokidar from "chokidar";
26
- import _ from "lodash";
27
- import { DebugBridge } from "./lpk_debug_bridge.js";
28
- import shellApi from "../shellapi.js";
29
- import { collectContextFromDockerFile } from "./lpk_devshell_docker.js";
22
+ } from "../utils.js"
23
+ import os from "node:os"
24
+ import commandExists from "command-exists"
25
+ import chokidar from "chokidar"
26
+ import _ from "lodash"
27
+ import { DebugBridge } from "./lpk_debug_bridge.js"
28
+ import shellApi from "../shellapi.js"
29
+ import { collectContextFromDockerFile } from "./lpk_devshell_docker.js"
30
30
 
31
31
  // 判断是否需要重新构建
32
32
  // - 先判断 lzc-build.yml 是否发生改变
@@ -36,39 +36,39 @@ import { collectContextFromDockerFile } from "./lpk_devshell_docker.js";
36
36
  // - 根据在 backend api 中判断同步的目录下是否存在文件 判断当前运行的 app 是否已经有一个挂载的实例,避免重复挂载
37
37
  class AppDevShellMonitor {
38
38
  constructor(cwd, pkgId, buildConfigFile) {
39
- this.pwd = cwd ? path.resolve(cwd) : process.cwd();
40
- this.pkgId = pkgId;
39
+ this.pwd = cwd ? path.resolve(cwd) : process.cwd()
40
+ this.pkgId = pkgId
41
41
 
42
- this.optionsFilePath = path.join(this.pwd, buildConfigFile);
43
- this.options = loadFromYaml(this.optionsFilePath);
42
+ this.optionsFilePath = path.join(this.pwd, buildConfigFile)
43
+ this.options = loadFromYaml(this.optionsFilePath)
44
44
 
45
45
  this.manifestFilePath = this.options["manifest"]
46
46
  ? path.join(this.pwd, this.options["manifest"])
47
- : path.join(this.pwd, "lzc-manifest.yml");
47
+ : path.join(this.pwd, "lzc-manifest.yml")
48
48
 
49
49
  this.hashObject = {
50
50
  build: "",
51
- manifest: "",
52
- };
53
- this.cacheFilePath = undefined;
54
- this.oldHash = undefined;
55
- this.newHash = undefined;
56
- this.bridge = new DebugBridge();
51
+ manifest: ""
52
+ }
53
+ this.cacheFilePath = undefined
54
+ this.oldHash = undefined
55
+ this.newHash = undefined
56
+ this.bridge = new DebugBridge()
57
57
  }
58
58
 
59
59
  async init() {
60
- const pathId = await md5String(this.pwd);
60
+ const pathId = await md5String(this.pwd)
61
61
  this.cacheFilePath = path.resolve(
62
62
  os.tmpdir(),
63
63
  "lzc-cli-devshell",
64
64
  pathId,
65
65
  "hash"
66
- );
67
- ensureDir(this.cacheFilePath);
66
+ )
67
+ ensureDir(this.cacheFilePath)
68
68
 
69
- await this.updateHash();
69
+ await this.updateHash()
70
70
 
71
- return this;
71
+ return this
72
72
  }
73
73
 
74
74
  async shouldBuild() {
@@ -76,373 +76,376 @@ class AppDevShellMonitor {
76
76
  this.change() ||
77
77
  (await this.bridge.status(this.pkgId)) === "NotInstalled" ||
78
78
  !(await this.bridge.isDevshell(this.pkgId))
79
- );
79
+ )
80
80
  }
81
81
 
82
82
  change() {
83
- logger.debug("oldHash", this.oldHash);
84
- logger.debug("newHash", this.newHash);
85
- return !_.isEqual(this.oldHash, this.newHash);
83
+ logger.debug("oldHash", this.oldHash)
84
+ logger.debug("newHash", this.newHash)
85
+ return !_.isEqual(this.oldHash, this.newHash)
86
86
  }
87
87
 
88
88
  async updateHash() {
89
89
  this.oldHash = isFileExist(this.cacheFilePath)
90
90
  ? JSON.parse(fs.readFileSync(this.cacheFilePath))
91
- : {};
91
+ : {}
92
92
  const buildHash = isFileExist(this.optionsFilePath)
93
93
  ? await md5File(this.optionsFilePath)
94
- : "";
94
+ : ""
95
95
  const manifestHash = isFileExist(this.manifestFilePath)
96
96
  ? await md5File(this.manifestFilePath)
97
- : "";
97
+ : ""
98
98
  this.newHash = {
99
99
  build: buildHash,
100
- manifest: manifestHash,
101
- };
100
+ manifest: manifestHash
101
+ }
102
102
  if (!_.isEqual(this.oldHash, this.newHash)) {
103
- fs.writeFileSync(this.cacheFilePath, JSON.stringify(this.newHash));
103
+ fs.writeFileSync(this.cacheFilePath, JSON.stringify(this.newHash))
104
104
  }
105
105
  }
106
106
  }
107
107
 
108
108
  export class AppDevShell {
109
109
  constructor(cwd, lpkBuild, forceBuild, buildConfigFile) {
110
- this.cwd = cwd;
111
- this.lpkBuild = lpkBuild;
112
- this.forceBuild = forceBuild;
113
- this.buildConfigFile = buildConfigFile;
114
- this.isUserApp = false;
115
- this.monitor = undefined;
110
+ this.cwd = cwd
111
+ this.lpkBuild = lpkBuild
112
+ this.forceBuild = forceBuild
113
+ this.buildConfigFile = buildConfigFile
114
+ this.isUserApp = false
115
+ this.monitor = undefined
116
116
  }
117
117
 
118
118
  async init() {
119
- const manifest = await this.lpkBuild.getManifest();
119
+ const manifest = await this.lpkBuild.getManifest()
120
120
  this.monitor = await new AppDevShellMonitor(
121
121
  this.cwd,
122
122
  manifest["package"],
123
123
  this.buildConfigFile
124
- ).init();
125
- this.isUserApp = isUserApp(manifest);
124
+ ).init()
125
+ this.isUserApp = isUserApp(manifest)
126
126
  }
127
127
 
128
128
  async build() {
129
129
  // 先判断是否需要重新构建
130
130
  if (this.forceBuild || (await this.monitor.shouldBuild())) {
131
- logger.debug("build...");
132
- await this.devshellBuild();
131
+ logger.debug("build...")
132
+ await this.devshellBuild()
133
133
  }
134
134
  }
135
135
 
136
136
  async devshellBuild() {
137
137
  this.lpkBuild.onBeforeBuildPackage(async (options) => {
138
- const devshell = options["devshell"];
138
+ const devshell = options["devshell"]
139
139
  if (!devshell) {
140
- throw "devshell 模式下,devshell 字段必须要指定";
140
+ throw "devshell 模式下,devshell 字段必须要指定"
141
141
  }
142
142
 
143
- const routes = devshell["routes"];
143
+ const routes = devshell["routes"]
144
144
  if (!routes || routes.length == 0) {
145
- throw "devshell 模式下,必须要指定 routes 内容";
145
+ throw "devshell 模式下,必须要指定 routes 内容"
146
146
  }
147
147
 
148
- return options;
149
- });
148
+ return options
149
+ })
150
150
 
151
151
  // 复制 busybox 到 devshell 中去
152
152
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
153
153
  const busyboxPath = path.join(
154
154
  contextDirname(import.meta.url),
155
155
  "../../template/_lpk/busybox-1.35.0"
156
- );
157
- let dest = path.join(contentdir, "devshell", "busybox");
158
- ensureDir(dest);
159
- fs.copyFileSync(busyboxPath, dest);
160
- fs.chmodSync(dest, 0o775);
161
- });
156
+ )
157
+ let dest = path.join(contentdir, "devshell", "busybox")
158
+ ensureDir(dest)
159
+ fs.copyFileSync(busyboxPath, dest)
160
+ fs.chmodSync(dest, 0o775)
161
+ })
162
162
 
163
163
  // 复制 init_debug_bridge.sh 到 devshell 中去
164
164
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
165
165
  const initPath = path.join(
166
166
  contextDirname(import.meta.url),
167
167
  "../../template/_lpk/init_debug_bridge.sh"
168
- );
169
- let dest = path.join(contentdir, "devshell", "init_debug_bridge.sh");
170
- ensureDir(dest);
171
- fs.copyFileSync(initPath, dest);
172
- fs.chmodSync(dest, 0o775);
173
- });
168
+ )
169
+ let dest = path.join(contentdir, "devshell", "init_debug_bridge.sh")
170
+ ensureDir(dest)
171
+ fs.copyFileSync(initPath, dest)
172
+ fs.chmodSync(dest, 0o775)
173
+ })
174
174
 
175
175
  // 复制 exec.sh 到 devshell 中去
176
176
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
177
177
  const execScriptPath = path.join(
178
178
  contextDirname(import.meta.url),
179
179
  "../../template/_lpk/exec.sh"
180
- );
181
- let dest = path.join(contentdir, "devshell", "exec.sh");
182
- ensureDir(dest);
183
- fs.copyFileSync(execScriptPath, dest);
184
- fs.chmodSync(dest, 0o775);
185
- });
180
+ )
181
+ let dest = path.join(contentdir, "devshell", "exec.sh")
182
+ ensureDir(dest)
183
+ fs.copyFileSync(execScriptPath, dest)
184
+ fs.chmodSync(dest, 0o775)
185
+ })
186
186
 
187
187
  // 复制 setupscript 脚本
188
188
  this.lpkBuild.onBeforeTarContent(async (contentdir, options) => {
189
- const devshell = options["devshell"];
189
+ const devshell = options["devshell"]
190
190
  if (!devshell["setupscript"]) {
191
- return;
191
+ return
192
192
  }
193
193
 
194
- logger.debug("处理 setupscript ");
195
- const dest = path.join(contentdir, "devshell", "setupscript");
196
- ensureDir(dest);
194
+ logger.debug("处理 setupscript ")
195
+ const dest = path.join(contentdir, "devshell", "setupscript")
196
+ ensureDir(dest)
197
197
 
198
198
  // 先判断是否文件
199
- const filePath = path.resolve(devshell["setupscript"]);
199
+ const filePath = path.resolve(devshell["setupscript"])
200
200
  if (isFileExist(filePath)) {
201
- fs.copyFileSync(filePath, dest);
201
+ fs.copyFileSync(filePath, dest)
202
202
  } else {
203
- fs.writeFileSync(
204
- dest,
205
- `#!/bin/sh\nset -ex\n${devshell["setupscript"]}`
206
- );
203
+ fs.writeFileSync(dest, `#!/bin/sh\nset -ex\n${devshell["setupscript"]}`)
207
204
  }
208
- fs.chmodSync(dest, 0o775);
209
- });
205
+ fs.chmodSync(dest, 0o775)
206
+ })
210
207
 
211
208
  // 在生成 manifest.yml 之前合并 devshell manifest 模板字段
212
209
  this.lpkBuild.onBeforeDumpYaml(async (manifest, options) => {
213
- logger.debug("merge lzc-build.yml devshell routes field");
214
- const devshell = options["devshell"];
210
+ logger.debug("merge lzc-build.yml devshell routes field")
211
+ const devshell = options["devshell"]
215
212
 
216
- const routes = devshell["routes"];
217
- logger.debug("options devshell delete 'routes' field");
218
- delete options["devshell"]["routes"];
213
+ const routes = devshell["routes"]
214
+ logger.debug("options devshell delete 'routes' field")
215
+ delete options["devshell"]["routes"]
219
216
 
220
217
  // 添加 devshell 必要路由
221
218
  routes.push(
222
219
  "/__debug.bridge=exec://80,/lzcapp/pkg/content/devshell/init_debug_bridge.sh"
223
- );
224
- routes.push("/__isdevshell=file:///lzcapp/pkg/devshell");
220
+ )
221
+ routes.push("/__isdevshell=file:///lzcapp/pkg/devshell")
225
222
 
226
223
  // 如果 devshell 中的 router 和 manifest 中的 prefix 出现冲突
227
224
  // 优先使用 devshell 中的。
228
225
  routes.forEach((r) => {
229
226
  if (!r) {
230
- return;
227
+ return
231
228
  }
232
229
 
233
- let prefix = r.split("=")[0];
230
+ let prefix = r.split("=")[0]
234
231
  let index = manifest["application"]["routes"].findIndex((mr) => {
235
232
  if (!mr) {
236
- return false;
233
+ return false
237
234
  }
238
- return mr.split("=")[0] == prefix;
239
- });
235
+ return mr.split("=")[0] == prefix
236
+ })
240
237
  if (index > -1) {
241
- manifest["application"]["routes"].splice(index, 1);
238
+ manifest["application"]["routes"].splice(index, 1)
242
239
  }
243
- });
244
- const application = { routes };
245
- return mergeYamlInMemory([manifest, { application }]);
246
- });
240
+ })
241
+ const application = { routes }
242
+ return mergeYamlInMemory([manifest, { application }])
243
+ })
247
244
 
248
245
  // 在生成 manifest.yml 之前合并 lzc-build.yml devshell 字段的值
249
246
  // 并加上 health_check 字段, 当处于 devshell 的情况时,禁用 health_check
250
247
  // 避免应用永远处于 unhealth 导致状态卡在 starting
251
248
  this.lpkBuild.onBeforeDumpYaml(async (manifest, options) => {
252
- logger.debug("merge lzc-build.yml devshell services\n", options);
253
- const userapp = this.isUserApp ? shellApi.uid + "." : "";
249
+ logger.debug("merge lzc-build.yml devshell services\n", options)
250
+ const userapp = this.isUserApp ? shellApi.uid + "." : ""
254
251
  const devshell = {
255
252
  application: {
256
253
  devshell: options["devshell"],
257
254
  health_check: {
258
255
  test_url: `http://${userapp}app.${manifest["package"]}.lzcapp/__isdevshell`,
259
- disable: true,
260
- },
261
- },
262
- };
263
- return mergeYamlInMemory([manifest, devshell]);
264
- });
256
+ disable: true
257
+ }
258
+ }
259
+ }
260
+ return mergeYamlInMemory([manifest, devshell])
261
+ })
265
262
 
266
263
  // 如果 services/devshell 中有 dependencies 字段,优先使用
267
264
  this.lpkBuild.onBeforeDumpYaml(async (manifest) => {
268
- const config = manifest["application"]["devshell"];
265
+ const config = manifest["application"]["devshell"]
269
266
  if (!config || !config["dependencies"]) {
270
- return manifest;
267
+ return manifest
271
268
  }
272
269
 
273
- const deps = config["dependencies"];
270
+ const deps = config["dependencies"]
274
271
  if (deps.length == 0) {
275
- logger.warn("dependencies 内容为空,跳过 dependencies");
276
- delete manifest["application"]["devshell"]["dependencies"];
277
- return manifest;
272
+ logger.warn("dependencies 内容为空,跳过 dependencies")
273
+ delete manifest["application"]["devshell"]["dependencies"]
274
+ return manifest
278
275
  }
279
276
 
280
- const depsStr = deps.sort().join(" ");
281
- logger.debug("开始创建 Dockerfile 文件");
277
+ const depsStr = deps.sort().join(" ")
278
+ logger.debug("开始创建 Dockerfile 文件")
282
279
 
283
- const tempDir = fs.mkdtempSync(".lzc-cli-build-dependencies");
280
+ const tempDir = fs.mkdtempSync(".lzc-cli-build-dependencies")
284
281
  try {
285
282
  const dockerfilePath = path.join(
286
283
  contextDirname(import.meta.url),
287
284
  "../../template/_lpk/Dockerfile.in"
288
- );
285
+ )
289
286
  await createTemplateFileCommon(
290
287
  dockerfilePath,
291
288
  path.join(tempDir, "Dockerfile"),
292
289
  { dependencies: depsStr }
293
- );
290
+ )
294
291
 
295
- const label = `${await md5String(depsStr)}:latest`;
296
- logger.debug(`开始在盒子中构建 ${label} 镜像 from ${tempDir}`);
292
+ const label = `${await md5String(depsStr)}:latest`
293
+ logger.debug(`开始在盒子中构建 ${label} 镜像 from ${tempDir}`)
297
294
 
298
295
  const contextTar = await collectContextFromDockerFile(
299
296
  tempDir,
300
297
  path.resolve(tempDir, "Dockerfile")
301
- );
302
- const bridge = new DebugBridge();
303
- const tag = await bridge.buildImage(label, contextTar);
304
- delete manifest["application"]["devshell"];
305
- manifest["application"]["image"] = tag;
298
+ )
299
+ const bridge = new DebugBridge()
300
+ const tag = await bridge.buildImage(label, contextTar)
301
+ delete manifest["application"]["devshell"]
302
+ manifest["application"]["image"] = tag
306
303
  } finally {
307
- fs.rmSync(tempDir, { recursive: true });
304
+ fs.rmSync(tempDir, { recursive: true })
308
305
  }
309
- return manifest;
310
- });
306
+ return manifest
307
+ })
311
308
 
312
309
  // 如果 services 中有 devshell 的字段,需要检测是否需要提前构建
313
310
  this.lpkBuild.onBeforeDumpYaml(async (manifest) => {
314
- const application = manifest["application"];
311
+ const application = manifest["application"]
315
312
  if (!application || !application["devshell"]) {
316
- return manifest;
313
+ return manifest
317
314
  }
318
315
 
319
- const config = manifest["application"]["devshell"];
316
+ const config = manifest["application"]["devshell"]
320
317
  if (!config || !config["build"]) {
321
- return manifest;
318
+ return manifest
322
319
  }
323
320
 
324
- const label = `${manifest["package"]}-devshell:${manifest["version"]}`;
325
- logger.debug(`开始在盒子中构建 ${label} 镜像`);
321
+ const label = `${manifest["package"]}-devshell:${manifest["version"]}`
322
+ logger.debug(`开始在盒子中构建 ${label} 镜像`)
326
323
 
327
324
  const contextTar = await collectContextFromDockerFile(
328
325
  process.cwd(),
329
326
  path.resolve(process.cwd(), config["build"], "Dockerfile")
330
- );
327
+ )
331
328
 
332
- const bridge = new DebugBridge();
333
- const tag = await bridge.buildImage(label, contextTar);
334
- delete manifest["application"]["devshell"];
335
- manifest["application"]["image"] = tag;
336
- return manifest;
337
- });
329
+ const bridge = new DebugBridge()
330
+ const tag = await bridge.buildImage(label, contextTar)
331
+ delete manifest["application"]["devshell"]
332
+ manifest["application"]["image"] = tag
333
+ return manifest
334
+ })
338
335
 
339
336
  // 如果 devshell 中指定了 image 字段将使用 image 字段
340
337
  this.lpkBuild.onBeforeDumpYaml(async (manifest) => {
341
- const config = manifest["application"];
338
+ const config = manifest["application"]
342
339
  if (config["devshell"] && config["devshell"]["image"]) {
343
- manifest["application"]["image"] = config["devshell"]["image"];
344
- delete manifest["application"]["devshell"];
340
+ manifest["application"]["image"] = config["devshell"]["image"]
341
+ delete manifest["application"]["devshell"]
345
342
  }
346
- return manifest;
347
- });
343
+ return manifest
344
+ })
348
345
 
349
346
  // 如果没有找到 devshell 中没有指定 image 不存在,将默认使用的 lzc-cli/devshell 容器
350
347
  this.lpkBuild.onBeforeDumpYaml(async (manifest) => {
351
- delete manifest["application"]["devshell"];
348
+ delete manifest["application"]["devshell"]
352
349
 
353
- const config = manifest["application"];
350
+ const config = manifest["application"]
354
351
  if (config["image"]) {
355
- return manifest;
352
+ return manifest
356
353
  }
357
354
 
358
- logger.debug("use default lzc-cli/devshell image");
359
- manifest["application"][
360
- "image"
361
- ] = `registry.lazycat.cloud/lzc-cli/devshell:v0.0.5`;
362
- return manifest;
363
- });
355
+ logger.debug("use default lzc-cli/devshell image")
356
+ manifest["application"]["image"] =
357
+ `registry.lazycat.cloud/lzc-cli/devshell:v0.0.5`
358
+ return manifest
359
+ })
364
360
 
365
361
  // 添加一个 devshell 的标记在 lpk 中,标记当前 lpk 为一个 debug 版本
366
362
  this.lpkBuild.onBeforeDumpLpk(async (options, cwd, destDir) => {
367
- fs.writeFileSync(path.resolve(destDir, "devshell"), "");
368
- });
363
+ fs.writeFileSync(path.resolve(destDir, "devshell"), "")
364
+ })
369
365
 
370
366
  // 在构建生成 lpk 包后,调用 deploy 进行部署
371
- let installer = new LpkInstaller();
372
- await installer.init();
373
- await installer.deploy(this.lpkBuild, true);
367
+ let installer = new LpkInstaller()
368
+ await installer.init()
369
+ await installer.deploy(this.lpkBuild, true)
374
370
  }
375
371
 
376
372
  async rsyncShell() {
377
- const manifest = await this.lpkBuild.getManifest();
378
- const pkgId = manifest["package"];
373
+ const manifest = await this.lpkBuild.getManifest()
374
+ const pkgId = manifest["package"]
379
375
 
380
- let isSync = false;
376
+ let isSync = false
381
377
  try {
382
- const locker = new FileLocker(pkgId);
383
- locker.lock();
378
+ const locker = new FileLocker(pkgId)
379
+ locker.lock()
384
380
  process.on("exit", () => {
385
- logger.debug("filelock unlock");
386
- locker.unlock();
387
- });
388
- isSync = true;
381
+ logger.debug("filelock unlock")
382
+ locker.unlock()
383
+ })
384
+ isSync = true
389
385
  } catch (err) {
390
- logger.debug("filelock catch");
391
- logger.debug(err);
386
+ logger.debug("filelock catch")
387
+ logger.debug(err)
392
388
  }
393
389
 
394
- const devshell = new DevShell(pkgId, this.isUserApp);
390
+ const devshell = new DevShell(pkgId, this.isUserApp)
395
391
  if (isSync) {
396
- await devshell.shell();
392
+ await devshell.shell()
397
393
  } else {
398
- await devshell.connectShell();
394
+ await devshell.connectShell()
399
395
  }
400
- logger.debug("exit shell");
396
+ logger.debug("exit shell")
401
397
  // TODO: shell 在正常情况下,按 Ctrl-D 就会退出,回到原来的本地的 shell ,但
402
398
  // 现在会一直卡在退出状态后,必须要另外手动的指定 pkill node
403
- process.exit(0);
399
+ process.exit(0)
404
400
  }
405
401
  }
406
402
 
407
403
  class DevShell {
408
404
  constructor(appId, isUserApp) {
409
- this.appId = appId;
410
- this.isUserApp = isUserApp;
405
+ this.appId = appId
406
+ this.isUserApp = isUserApp
411
407
  }
412
408
 
413
409
  async syncProject(appId) {
414
410
  // prettier-ignore
415
- const resolvedIp = await resolveDomain(this.domain);
411
+ const resolvedIp = await resolveDomain(`dev.${shellApi.boxname}.heiyu.space`);
416
412
  let rsh = [
417
413
  "ssh",
418
- "-J", `box@${resolvedIp}:22222`,
419
- "-p", `22222`,
420
- "-o", `"StrictHostKeyChecking=no"`,
421
- "-o", `"UserKnownHostsFile=/dev/null"`,
422
- "-o", `"ConnectionAttempts=3"`,
423
- "-o", `"ConnectTimeout=30"`,
424
- "-o", `${isDebugMode() ? '"LogLevel=DEBUG"' :'"LogLevel=ERROR"'}`,
425
- ].join(" ");
414
+ "-J",
415
+ `box@[${resolvedIp}]:22222`,
416
+ "-p",
417
+ `22222`,
418
+ "-o",
419
+ `"StrictHostKeyChecking=no"`,
420
+ "-o",
421
+ `"UserKnownHostsFile=/dev/null"`,
422
+ "-o",
423
+ `"ConnectionAttempts=3"`,
424
+ "-o",
425
+ `"ConnectTimeout=30"`,
426
+ "-o",
427
+ `${isDebugMode() ? '"LogLevel=DEBUG"' : '"LogLevel=ERROR"'}`
428
+ ].join(" ")
426
429
  // 检查rsync工具是否存在:提示用户
427
- const rsyncExisted = commandExists.sync("rsync");
430
+ const rsyncExisted = commandExists.sync("rsync")
428
431
  if (!rsyncExisted) {
429
- logger.error("请检查 rsync 是否安装,路径是否正确!");
430
- process.exit(1);
432
+ logger.error("请检查 rsync 是否安装,路径是否正确!")
433
+ process.exit(1)
431
434
  }
432
435
 
433
- const rsyncDebug = isDebugMode() ? "-P" : "";
436
+ const rsyncDebug = isDebugMode() ? "-P" : ""
434
437
  const host = this.isUserApp
435
438
  ? `${shellApi.uid}.app.${appId}.lzcapp`
436
- : `app.${appId}.lzcapp`;
437
- const dest = `root@${host}:/lzcapp/cache/devshell`;
439
+ : `app.${appId}.lzcapp`
440
+ const dest = `root@${host}:/lzcapp/cache/devshell`
438
441
  try {
439
442
  execSync(
440
443
  `rsync ${rsyncDebug} --rsh='${rsh}' --recursive --relative --perms --update -F --filter=':- .gitignore' --ignore-errors . ${dest}`,
441
444
  { stdio: ["ignore", "inherit", "inherit"] }
442
- );
445
+ )
443
446
  } catch (err) {
444
- logger.error("rsync 同步失败");
445
- logger.debug(err);
447
+ logger.error("rsync 同步失败")
448
+ logger.debug(err)
446
449
  }
447
450
  }
448
451
 
@@ -452,77 +455,73 @@ class DevShell {
452
455
  // fs.watch 虽然不支持递归,但可以直接监听整个文件夹的变动
453
456
  async fallbackWatch(filepath, gitignore, callback) {
454
457
  if (gitignore.contain(filepath)) {
455
- return Promise.resolve();
458
+ return Promise.resolve()
456
459
  }
457
460
 
458
461
  if (filepath.endsWith(".git") || filepath.endsWith(".lazycat")) {
459
- return Promise.resolve();
462
+ return Promise.resolve()
460
463
  }
461
464
 
462
- fs.watch(filepath, callback(filepath));
465
+ fs.watch(filepath, callback(filepath))
463
466
 
464
467
  // 如果为一个文件夹,则扫描当中是否含有子文件夹
465
468
  if (isDirSync(filepath)) {
466
469
  return gitignore.readdir(filepath, (err, files) => {
467
470
  if (err) {
468
- throw err;
471
+ throw err
469
472
  }
470
473
 
471
474
  if (files.length <= 0) {
472
- return;
475
+ return
473
476
  }
474
477
 
475
478
  files.forEach((f) => {
476
479
  if (f.isDirectory()) {
477
- this.fallbackWatch(
478
- path.join(filepath, f.name),
479
- gitignore,
480
- callback
481
- );
480
+ this.fallbackWatch(path.join(filepath, f.name), gitignore, callback)
482
481
  }
483
- });
484
- });
482
+ })
483
+ })
485
484
  }
486
485
  }
487
486
 
488
487
  // 监听非.gitignore文件
489
488
  // TODO: 目前仅仅监听process.cwd()以下的文件
490
489
  async watchFile(appId) {
491
- const ignore = new GitIgnore(process.cwd());
492
- await ignore.collect();
490
+ const ignore = new GitIgnore(process.cwd())
491
+ await ignore.collect()
493
492
  chokidar
494
493
  .watch(".", {
495
494
  ignored: (path) => {
496
- if ([".git", ".lazycat"].some((p) => path.startsWith(p))) return true;
495
+ if ([".git", ".lazycat"].some((p) => path.startsWith(p))) return true
497
496
 
498
- return ignore.contain(path);
497
+ return ignore.contain(path)
499
498
  },
500
- ignoreInitial: true,
499
+ ignoreInitial: true
501
500
  })
502
501
  .on(
503
502
  "all",
504
503
  debounce(() => {
505
- this.syncProject(appId);
504
+ this.syncProject(appId)
506
505
  }, 1000)
507
- );
506
+ )
508
507
  }
509
508
 
510
509
  async shell() {
511
510
  try {
512
511
  // 监听文件
513
- await this.watchFile(this.appId);
512
+ await this.watchFile(this.appId)
514
513
  await this.connectShell(async () => {
515
514
  // 在连接成功的时候,同步一次文件
516
- await this.syncProject(this.appId);
517
- });
515
+ await this.syncProject(this.appId)
516
+ })
518
517
  } catch (e) {
519
- console.log(e);
520
- return Promise.reject(e);
518
+ console.log(e)
519
+ return Promise.reject(e)
521
520
  }
522
521
  }
523
522
 
524
523
  async connectShell(onconnect = null) {
525
- const bridge = new DebugBridge();
526
- await bridge.devshell(this.appId, this.isUserApp, onconnect);
524
+ const bridge = new DebugBridge()
525
+ await bridge.devshell(this.appId, this.isUserApp, onconnect)
527
526
  }
528
527
  }