@lazycatcloud/lzc-cli 1.2.53 → 1.2.55

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/changelog.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 1.2.55
2
+
3
+ 1. 添加 lzc-docker 命令
4
+ 2. 添加 lzc-docker-compose 命令
5
+ 3. 添加 deploy_params 打包支持
6
+ 4. 添加 lzc-cli 版本检测
7
+ 5. 修复 lzc-cli zsh/bash 补全错误
8
+ 6. 隐藏 triggerApk 错误
9
+
10
+ # 1.2.54
11
+
12
+ 1. 添加 lzc-cli docker 命令
13
+ 2. 添加 lzc-cli docker-compose 命令
14
+ 3. 修复其他同步卡顿问题
15
+
1
16
  # 1.2.53
2
17
 
3
18
  1. 修复 devshell 模型下,环境变量中有空格导致export错误
@@ -29,6 +29,6 @@ export async function triggerApk(id, name, iconPath) {
29
29
  throw `请求生成应用出错! 使用 --apk=n 停止生成APK`
30
30
  }
31
31
  } catch (error) {
32
- logger.error(error)
32
+ logger.debug(error)
33
33
  }
34
34
  }
package/lib/app/index.js CHANGED
@@ -5,7 +5,7 @@ import { AppDevShell } from "./lpk_devshell.js"
5
5
  import { LpkInstaller, installConfig } from "./lpk_installer.js"
6
6
  import logger from "loglevel"
7
7
  import { sleep, checkRsync } from "../utils.js"
8
- import { DebugBridge } from "./lpk_debug_bridge.js"
8
+ import { DebugBridge } from "../debug_bridge.js"
9
9
  import shellApi from "../shellapi.js"
10
10
  import { generate } from "./lpk_create_generator.js"
11
11
 
@@ -147,6 +147,7 @@ export function lpkAppCommand(program) {
147
147
  await shellApi.init()
148
148
 
149
149
  const bridge = new DebugBridge()
150
+ await bridge.init()
150
151
  await bridge.uninstall(pkgId)
151
152
  }
152
153
  },
@@ -157,6 +158,7 @@ export function lpkAppCommand(program) {
157
158
  await shellApi.init()
158
159
 
159
160
  const bridge = new DebugBridge()
161
+ await bridge.init()
160
162
  const status = await bridge.status(pkgId)
161
163
  console.log(status)
162
164
  }
@@ -76,6 +76,33 @@ async function fetchIconTo(options, cwd, destDir) {
76
76
  return
77
77
  }
78
78
 
79
+ async function fetchLzcDeployParamTo(options, cwd, destDir) {
80
+ let deployParamsPath = options["deploy_params"]
81
+ if (!deployParamsPath) {
82
+ logger.debug("deploy_params 没有指定")
83
+ let cwdDeployParamsPath = path.join(cwd, "lzc-deploy-params.yml")
84
+ if (isFileExist(cwdDeployParamsPath)) {
85
+ deployParamsPath = cwdDeployParamsPath
86
+ logger.debug("检测当前目录下具有 lzc-deploy-params.yml")
87
+ }
88
+ }
89
+ if (!deployParamsPath) {
90
+ return
91
+ }
92
+
93
+ if (!path.isAbsolute(deployParamsPath)) {
94
+ deployParamsPath = path.resolve(cwd, deployParamsPath)
95
+ }
96
+
97
+ if (!isFileExist(deployParamsPath)) {
98
+ logger.warn(`deploy_params ${deployParamsPath} 不存在`)
99
+ return
100
+ }
101
+
102
+ fs.copyFileSync(deployParamsPath, path.join(destDir, "deploy_params.yml"))
103
+ return
104
+ }
105
+
79
106
  // 提供一些方便的环境变量,可以在 lzc-build.yml 中直接使用
80
107
  // - LocalIP 本地局域网ip
81
108
  function localIp() {
@@ -137,7 +164,7 @@ export class LpkBuild {
137
164
  this.beforeBuildPackageFn = []
138
165
  this.beforeDumpYamlFn = []
139
166
  this.beforeTarContentFn = []
140
- this.beforeDumpLpkFn = [fetchIconTo]
167
+ this.beforeDumpLpkFn = [fetchIconTo, fetchLzcDeployParamTo]
141
168
  }
142
169
 
143
170
  // init 时替换 lzc-build.yml 中的模板字段
@@ -14,7 +14,6 @@ import {
14
14
  md5String,
15
15
  md5File,
16
16
  loadFromYaml,
17
- FileLocker,
18
17
  isUserApp,
19
18
  createTemplateFileCommon,
20
19
  isDebugMode,
@@ -27,7 +26,7 @@ import {
27
26
  import os from "node:os"
28
27
  import chokidar from "chokidar"
29
28
  import _ from "lodash"
30
- import { DebugBridge } from "./lpk_debug_bridge.js"
29
+ import { DebugBridge } from "../debug_bridge.js"
31
30
  import shellApi from "../shellapi.js"
32
31
  import { collectContextFromDockerFile } from "./lpk_devshell_docker.js"
33
32
 
@@ -70,6 +69,7 @@ class AppDevShellMonitor {
70
69
  ensureDir(this.cacheFilePath)
71
70
 
72
71
  await this.updateHash()
72
+ await this.bridge.init()
73
73
 
74
74
  return this
75
75
  }
@@ -280,7 +280,6 @@ export class AppDevShell {
280
280
  application: {
281
281
  devshell: options["devshell"],
282
282
  health_check: {
283
- test_url: `http://${userapp}app.${manifest["package"]}.lzcapp/__isdevshell`,
284
283
  disable: true
285
284
  }
286
285
  }
@@ -329,6 +328,7 @@ export class AppDevShell {
329
328
  path.resolve(tempDir, "Dockerfile")
330
329
  )
331
330
  const bridge = new DebugBridge()
331
+ await bridge.init()
332
332
  const tag = await bridge.buildImage(label, contextTar)
333
333
  delete manifest["application"]["devshell"]
334
334
  manifest["application"]["image"] = tag
@@ -359,6 +359,7 @@ export class AppDevShell {
359
359
  )
360
360
 
361
361
  const bridge = new DebugBridge()
362
+ await bridge.init()
362
363
  const tag = await bridge.buildImage(label, contextTar)
363
364
  delete manifest["application"]["devshell"]
364
365
  manifest["application"]["image"] = tag
@@ -410,28 +411,9 @@ export class AppDevShell {
410
411
  async rsyncShell() {
411
412
  const manifest = await this.lpkBuild.getManifest()
412
413
  const pkgId = manifest["package"]
413
-
414
- let isSync = false
415
- try {
416
- const locker = new FileLocker(pkgId)
417
- locker.lock()
418
- process.on("exit", () => {
419
- logger.debug("filelock unlock")
420
- locker.unlock()
421
- })
422
- isSync = true
423
- } catch (err) {
424
- logger.debug("filelock catch")
425
- logger.debug(err)
426
- }
427
-
428
414
  const devshell = new DevShell(pkgId, this.isUserApp)
429
415
  try {
430
- if (isSync) {
431
- await devshell.shell()
432
- } else {
433
- await devshell.connectShell()
434
- }
416
+ await devshell.shell()
435
417
  } catch (e) {
436
418
  logger.error(`devshell 错误: ${e}`)
437
419
  }
@@ -453,10 +435,8 @@ class DevShell {
453
435
  `dev.${shellApi.boxname}.heiyu.space`
454
436
  )
455
437
  const rsyncDebug = isDebugMode() ? "-P" : ""
456
- const host = this.isUserApp
457
- ? `${shellApi.uid}.app.${appId}.lzcapp`
458
- : `app.${appId}.lzcapp`
459
- const dest = `rsync://${host}@[${resolvedIp}]:873/lzcapp/cache/devshell`
438
+ const destDir = `${appId}${this.isUserApp ? "/" + shellApi.uid : ""}`
439
+ const dest = `rsync://${shellApi.uid}@[${resolvedIp}]:874/lzcapp_cache/${destDir}/devshell`
460
440
  const rsyncCmd = isWindows
461
441
  ? path.join(
462
442
  contextDirname(import.meta.url),
@@ -564,6 +544,7 @@ class DevShell {
564
544
 
565
545
  async connectShell(onconnect = null) {
566
546
  const bridge = new DebugBridge()
547
+ await bridge.init()
567
548
  await bridge.devshell(this.appId, this.isUserApp, onconnect)
568
549
  }
569
550
  }
@@ -2,7 +2,7 @@ import logger from "loglevel"
2
2
  import fs from "node:fs"
3
3
  import path from "node:path"
4
4
  import { loadFromYaml, Downloader, unzipSync } from "../utils.js"
5
- import { DebugBridge } from "./lpk_debug_bridge.js"
5
+ import { DebugBridge } from "../debug_bridge.js"
6
6
  import shellapi from "../shellapi.js"
7
7
  import { triggerApk } from "./apkshell.js"
8
8
 
@@ -118,6 +118,7 @@ export class LpkInstaller {
118
118
  }
119
119
 
120
120
  const bridge = new DebugBridge()
121
+ await bridge.init()
121
122
  logger.info("开始安装应用")
122
123
  await bridge.install(pkgPath, manifest["package"])
123
124
  logger.info("\n")
@@ -1,6 +1,6 @@
1
1
  import spawn from "cross-spawn"
2
2
  import fs from "node:fs"
3
- import shellApi from "../shellapi.js"
3
+ import shellApi from "./shellapi.js"
4
4
  import {
5
5
  isDebugMode,
6
6
  isTraceMode,
@@ -10,7 +10,7 @@ import {
10
10
  isWindows,
11
11
  contextDirname,
12
12
  compareVersions
13
- } from "../utils.js"
13
+ } from "./utils.js"
14
14
  import logger from "loglevel"
15
15
  import commandExists from "command-exists"
16
16
  import path from "node:path"
@@ -40,6 +40,13 @@ export class DebugBridge {
40
40
  this.domain = `dev.${this.boxname}.heiyu.space`
41
41
  }
42
42
 
43
+ async init() {
44
+ if (!(await this.canPublicKey())) {
45
+ // 如果不能 ssh public key 登录则提示授权申请,否则后面可能会出现 rsync 询问密码的问题
46
+ await this.sshApplyGrant()
47
+ }
48
+ }
49
+
43
50
  async common(cmd, args) {
44
51
  const resolvedIp = await resolveDomain(this.domain)
45
52
  args = args.map((arg) => arg.replace(this.domain, resolvedIp))
@@ -59,11 +66,6 @@ export class DebugBridge {
59
66
  }
60
67
 
61
68
  async install(lpkPath, pkgId) {
62
- if (!(await this.canPublicKey())) {
63
- // 如果不能 ssh public key 登录则直接调用 ssh-copy-id 复制,否则后面可能会出现 rsync 询问密码的问题
64
- await this.sshCopyId()
65
- }
66
-
67
69
  const stream = fs.createReadStream(lpkPath)
68
70
  const resolvedIp = await resolveDomain(this.domain)
69
71
  const ssh = spawn(
@@ -86,36 +88,28 @@ export class DebugBridge {
86
88
  }
87
89
 
88
90
  async canPublicKey() {
89
- // FIXME: 目前没有找到在允许空密码的情况下,检测是否只能通过 publickey 登录的方法。
90
- return false
91
+ try {
92
+ await this.common(sshBinary(), [...sshCmdArgs(`box@${this.domain}`)])
93
+ return true
94
+ } catch {
95
+ return false
96
+ }
91
97
  }
92
98
 
93
- async sshCopyId() {
99
+ async sshApplyGrant() {
94
100
  const sshInfo = await findSshPublicKey()
95
101
  logger.debug("ssh public key info", sshInfo)
96
102
 
97
- const resolvedIp = await resolveDomain(this.domain)
98
- logger.debug("ip", resolvedIp)
103
+ const pk = Buffer.from(sshInfo.content.trimLeft()).toString("base64")
99
104
 
100
- // 将当前机器上的ssh public key 写到开发者工具中去,并过滤到重复的,管道在执行前会被清空,需要使用一个中间文件
101
- const stream = spawn.sync(
102
- sshBinary(),
103
- [...sshCmdArgs(`box@${resolvedIp}`), `add-ssh-public-key`],
104
- {
105
- input: sshInfo.content.trimLeft(),
106
- shell: true,
107
- encoding: "utf-8",
108
- stdio: "pipe"
109
- }
105
+ logger.warn(
106
+ `检测到您当前没有授权,请点击下面的连接在浏览器中完成授权,才能使用当前的机器的 ssh public key 访问开发者工具.
107
+ -> https://${this.domain}/auth?key=${pk}
108
+
109
+ 如果您的 '懒猫开发者工具' 不是 0.2.0 及以上版本,请先到应用商店进行升级.
110
+ `
110
111
  )
111
- if (stream.status != 0) {
112
- const stderr = stream.stderr.toString("utf-8")
113
- const stdout = stream.stdout.toString("utf-8")
114
- throw stdout + stderr
115
- }
116
- if (stream.error) {
117
- throw stream.error
118
- }
112
+ throw "请在授权完成后重试!"
119
113
  }
120
114
 
121
115
  async status(appId) {
@@ -127,9 +121,10 @@ export class DebugBridge {
127
121
  }
128
122
 
129
123
  async isDevshell(appId) {
124
+ await this.backendVersion020()
130
125
  const stdout = await this.common(sshBinary(), [
131
126
  ...sshCmdArgs(`box@${this.domain}`),
132
- `isDevshell --uid ${this.uid}`,
127
+ `isDevshellV2 --uid ${this.uid}`,
133
128
  appId
134
129
  ])
135
130
  return stdout == "true"
@@ -166,6 +161,8 @@ export class DebugBridge {
166
161
  }
167
162
 
168
163
  async devshell(appId, isUserApp, onconnect = null) {
164
+ await this.backendVersion020()
165
+
169
166
  let waiting = true
170
167
  while (waiting) {
171
168
  if (await this.isDevshell(appId)) {
@@ -237,4 +234,55 @@ export class DebugBridge {
237
234
  fs.rmSync(contextTar)
238
235
  })
239
236
  }
237
+
238
+ async lzcDocker(argv) {
239
+ await this.backendVersion020()
240
+
241
+ const resolvedIp = await resolveDomain(this.domain)
242
+ const stream = spawn(
243
+ sshBinary(),
244
+ [...sshCmdArgs(`box@${resolvedIp}`), "-t", "lzc-docker", ...argv],
245
+ {
246
+ shell: true,
247
+ stdio: "inherit"
248
+ }
249
+ )
250
+ return new Promise((resolve, reject) => {
251
+ stream.on("close", (code) => {
252
+ code == 0 ? resolve() : reject()
253
+ })
254
+ })
255
+ }
256
+
257
+ async lzcDockerCompose(argv) {
258
+ await this.backendVersion020()
259
+
260
+ const resolvedIp = await resolveDomain(this.domain)
261
+ const stream = spawn(
262
+ sshBinary(),
263
+ [...sshCmdArgs(`box@${resolvedIp}`), "-t", "lzc-docker-compose", ...argv],
264
+ {
265
+ shell: true,
266
+ stdio: "inherit"
267
+ }
268
+ )
269
+ return new Promise((resolve, reject) => {
270
+ stream.on("close", (code) => {
271
+ code == 0 ? resolve() : reject()
272
+ })
273
+ })
274
+ }
275
+
276
+ async backendVersion020() {
277
+ const backendVersion = await this.version()
278
+ if (compareVersions("0.2.0", backendVersion) < 0) {
279
+ logger.warn(`
280
+ 检测到您当前的 lzc-cli 版本较新,而 '懒猫开发者工具' 比较旧,请先到微服的商店升级 '懒猫开发者工具',点击下面的连接跳转:
281
+
282
+ -> https://appstore.${this.boxname}.heiyu.space/#/shop/detail/cloud.lazycat.developer.tools
283
+ `)
284
+ process.exit(1)
285
+ return
286
+ }
287
+ }
240
288
  }
@@ -0,0 +1,105 @@
1
+ import { DebugBridge } from "../debug_bridge.js"
2
+ import shellApi from "../shellapi.js"
3
+ import { isFileExist, isUserApp, loadFromYaml } from "../utils.js"
4
+ import logger from "loglevel"
5
+ import path from "node:path"
6
+
7
+ function dockerMiddleware(argv, yargs) {
8
+ if (argv.$0 == "lzc-docker" || argv.$0 == "lzc-docker-compose") {
9
+ argv.dockerArgs = argv._
10
+ return
11
+ }
12
+
13
+ argv.dockerArgs = []
14
+ // 找到 'docker-compose' 或者 ’docker’ 在参数中的位置
15
+ let index = argv._.indexOf("docker-compose")
16
+ if (index === -1) {
17
+ index = argv._.indexOf("docker")
18
+ }
19
+
20
+ if (index !== -1 && index < argv._.length - 1) {
21
+ // 获取原始的命令行参数
22
+ const originalArgs = argv._
23
+
24
+ // 将 'docker-compose' 或者 ’docker’ 之后的所有参数(包括选项)移到 dockerArgs 数组中
25
+ argv.dockerArgs = originalArgs.slice(index + 1)
26
+
27
+ // 从原始参数中移除这些参数
28
+ argv._ = argv._.slice(0, index + 1)
29
+
30
+ // 移除已经被处理的参数
31
+ for (const arg of argv.dockerArgs) {
32
+ delete argv[arg]
33
+ }
34
+ }
35
+ return argv
36
+ }
37
+
38
+ function builder(args) {
39
+ // 禁用严格模式,允许未知参数
40
+ return args
41
+ .parserConfiguration({
42
+ "unknown-options-as-args": true
43
+ })
44
+ .middleware(dockerMiddleware)
45
+ .strict(false)
46
+ }
47
+
48
+ export function singleLzcDockerCommand(commandName = "docker") {
49
+ return {
50
+ command: commandName,
51
+ desc: "微服应用 docker 管理",
52
+ builder: builder,
53
+ handler: async (args) => {
54
+ logger.debug("args: ", args)
55
+ await shellApi.init()
56
+ const bridge = new DebugBridge()
57
+ await bridge.init()
58
+ logger.debug("docker", args.dockerArgs)
59
+ await bridge.lzcDocker(args.dockerArgs)
60
+ }
61
+ }
62
+ }
63
+
64
+ export function singleLzcDockerComposeCommand(commandName = "docker-compose") {
65
+ return {
66
+ command: commandName,
67
+ desc: "微服应用 docker-compose 管理",
68
+ builder: builder,
69
+ handler: async (args) => {
70
+ logger.debug("args: ", args)
71
+ await shellApi.init()
72
+ let manifest = null
73
+ try {
74
+ for (let name of ["lzc-manifest.yml", "manifest.yml"]) {
75
+ const mpath = path.join(process.cwd(), name)
76
+ if (isFileExist(mpath)) {
77
+ manifest = loadFromYaml(mpath)
78
+ break
79
+ }
80
+ }
81
+ } catch (e) {
82
+ logger.debug("load manifest: ", e)
83
+ }
84
+ const pkgId = manifest ? manifest["package"] : ""
85
+ const userApp = manifest ? isUserApp(manifest) : false
86
+
87
+ const bridge = new DebugBridge()
88
+ await bridge.init()
89
+ const options = args.dockerArgs
90
+ if (pkgId != "" && !options.some((o) => o == "--project-directory")) {
91
+ options.unshift(
92
+ "--project-directory",
93
+ `/lzcapp/run/lzc-docker/compose/${pkgId}${userApp ? "/" + shellapi.uid : ""}`
94
+ )
95
+ }
96
+ logger.debug("docker-compose", options.join(" "))
97
+ await bridge.lzcDockerCompose(options)
98
+ }
99
+ }
100
+ }
101
+
102
+ export function lzcDockerCommand(program) {
103
+ program.command(singleLzcDockerCommand())
104
+ program.command(singleLzcDockerComposeCommand())
105
+ }
package/lib/log.js ADDED
@@ -0,0 +1,47 @@
1
+ import chalk from "chalk"
2
+ import logger from "loglevel"
3
+
4
+ export function initLogger() {
5
+ // logger level middleware
6
+ const logLevelOriginalFactory = logger.methodFactory
7
+ logger.methodFactory = function (methodName, logLevel, loggerName) {
8
+ let debug = logLevel <= logger.levels.DEBUG
9
+ let rawMethod = logLevelOriginalFactory(methodName, logLevel, loggerName)
10
+ return function (...args) {
11
+ let color = (msg) => chalk.gray
12
+ switch (methodName) {
13
+ case "trace":
14
+ color = chalk.dim.cyan
15
+ break
16
+ case "debug":
17
+ color = chalk.blue
18
+ break
19
+ case "info":
20
+ color = chalk.green
21
+ break
22
+ case "warn":
23
+ color = chalk.magenta
24
+ break
25
+ case "error":
26
+ color = chalk.bold.red
27
+ break
28
+ }
29
+ const prefix = loggerName ?? methodName
30
+ rawMethod(
31
+ (debug ? `[${prefix}] ` : "") +
32
+ args
33
+ .map((a) => {
34
+ let res = a
35
+ if (typeof a == "object") {
36
+ res = JSON.stringify(a, undefined, 4)
37
+ }
38
+ return color(res)
39
+ })
40
+ .join(" ")
41
+ )
42
+ }
43
+ }
44
+ logger.setDefaultLevel("info")
45
+ }
46
+
47
+ initLogger()
package/lib/utils.js CHANGED
@@ -19,6 +19,7 @@ import dns from "node:dns/promises"
19
19
  import axios from "axios"
20
20
  import AdmZip from "adm-zip"
21
21
  import commandExists from "command-exists"
22
+ import fetch from "node-fetch"
22
23
 
23
24
  // lzc-cli 包的 pkgInfo 信息
24
25
  export const pkgInfo = JSON.parse(
@@ -27,6 +28,27 @@ export const pkgInfo = JSON.parse(
27
28
  )
28
29
  )
29
30
 
31
+ export async function getLatestVersion(controller, pkgName = pkgInfo.name) {
32
+ const url = `https://data.jsdelivr.com/v1/package/npm/${pkgName}`
33
+ try {
34
+ logger.debug("check latest lzc-cli version...")
35
+ const data = await fetch(url, {
36
+ signal: controller.signal
37
+ })
38
+ const content = await data.json()
39
+ const latestVersion = content["tags"]["latest"]
40
+ if (latestVersion != pkgInfo.version) {
41
+ logger.warn(
42
+ `检测到 ${pkgName} 最新版本为 ${latestVersion},使用 'npm i -g ${pkgName}@${latestVersion}' 升级到最新版本!`
43
+ )
44
+ } else {
45
+ logger.debug(`已经在最新版本: ${latestVersion}`)
46
+ }
47
+ } catch (err) {
48
+ logger.debug(`请求 ${url} 失败, error: ${err}`)
49
+ }
50
+ }
51
+
30
52
  // 创建 Axios 实例
31
53
  export const api = axios.create()
32
54
 
@@ -353,45 +375,6 @@ export class Downloader {
353
375
  }
354
376
  }
355
377
 
356
- export class FileLocker {
357
- constructor(id) {
358
- this.filename = undefined
359
- this.fd = undefined
360
- this.id = id
361
- }
362
- lock() {
363
- this.filename = path.resolve(os.tmpdir(), "lzc-cli-file-lock", this.id)
364
- ensureDir(this.filename)
365
-
366
- try {
367
- this.fd = fs.openSync(this.filename, "wx+")
368
- } catch (e) {
369
- if (e.code == "EEXIST" && !this.withOpen(this.filename)) {
370
- logger.debug("filelock exist open with w+")
371
- this.fd = fs.openSync(this.filename, "w+")
372
- } else {
373
- throw e
374
- }
375
- }
376
- }
377
- unlock() {
378
- if (this.fd) {
379
- fs.closeSync(this.fd)
380
- fs.rmSync(this.filename)
381
- this.fd = undefined
382
- this.filename = undefined
383
- }
384
- }
385
- withOpen(filename) {
386
- const p = spawn.sync("lsof", ["-w", "-t", filename])
387
- if (p.status === 0) {
388
- return true
389
- } else {
390
- return false
391
- }
392
- }
393
- }
394
-
395
378
  export function isValidAppId(appId) {
396
379
  const regex = new RegExp("^(?!-)(?!.*--)[a-z][a-z0-9]*([-][a-z0-9]+)*$")
397
380
  return regex.test(appId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.53",
3
+ "version": "1.2.55",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
6
  "prepublishOnly": "node check-changelog.js"
@@ -12,7 +12,9 @@
12
12
  "changelog.md"
13
13
  ],
14
14
  "bin": {
15
- "lzc-cli": "scripts/cli.js"
15
+ "lzc-cli": "scripts/cli.js",
16
+ "lzc-docker": "scripts/lzc-docker.js",
17
+ "lzc-docker-compose": "scripts/lzc-docker-compose.js"
16
18
  },
17
19
  "type": "module",
18
20
  "keywords": [
package/scripts/cli.js CHANGED
@@ -5,58 +5,32 @@ import fs from "fs"
5
5
  import logger from "loglevel"
6
6
  import yargs from "yargs"
7
7
  import { hideBin } from "yargs/helpers"
8
- import chalk from "chalk"
8
+ import "../lib/log.js" // init logger
9
9
 
10
- import { contextDirname, pkgInfo } from "../lib/utils.js"
10
+ import { contextDirname, pkgInfo, getLatestVersion } from "../lib/utils.js"
11
11
  import { boxCommand } from "../lib/box/index.js"
12
12
  import { appstoreCommand } from "../lib/appstore/index.js"
13
13
  import { lpkAppCommand, lpkProjectCommand } from "../lib/app/index.js"
14
14
  import { configCommand } from "../lib/config/index.js"
15
+ import { lzcDockerCommand } from "../lib/docker/index.js"
15
16
 
16
- // logger level middleware
17
- const logLevelOriginalFactory = logger.methodFactory
18
- logger.methodFactory = function (methodName, logLevel, loggerName) {
19
- let debug = logLevel <= logger.levels.DEBUG
20
- let rawMethod = logLevelOriginalFactory(methodName, logLevel, loggerName)
21
- return function (...args) {
22
- let color = (msg) => chalk.gray
23
- switch (methodName) {
24
- case "trace":
25
- color = chalk.dim.cyan
26
- break
27
- case "debug":
28
- color = chalk.blue
29
- break
30
- case "info":
31
- color = chalk.green
32
- break
33
- case "warn":
34
- color = chalk.magenta
35
- break
36
- case "error":
37
- color = chalk.bold.red
38
- break
39
- }
40
- const prefix = loggerName ?? methodName
41
- rawMethod(
42
- (debug ? `[${prefix}] ` : "") +
43
- args
44
- .map((a) => {
45
- let res = a
46
- if (typeof a == "object") {
47
- res = JSON.stringify(a, undefined, 4)
48
- }
49
- return color(res)
50
- })
51
- .join(" ")
52
- )
53
- }
54
- }
55
- logger.setDefaultLevel("info")
56
17
  function setLoggerLevel({ log }) {
57
18
  logger.setLevel(log, false)
58
19
  }
59
20
 
21
+ function checkLatestVersion(controller) {
22
+ return ({ _: args }) => {
23
+ if (args.length > 0) {
24
+ switch (args[0]) {
25
+ case "project":
26
+ case "app":
27
+ case "appstore":
28
+ getLatestVersion(controller)
29
+ }
30
+ }
31
+ }
32
+ }
33
+
60
34
  const program = yargs(hideBin(process.argv))
61
35
  .scriptName("lzc-cli")
62
36
  .usage("<command> [options]")
@@ -78,27 +52,34 @@ boxCommand(program)
78
52
  lpkAppCommand(program)
79
53
  lpkProjectCommand(program)
80
54
  appstoreCommand(program)
55
+ lzcDockerCommand(program)
81
56
 
82
57
  // 当没有参数的时候,默认显示帮助。
83
58
  ;(async () => {
59
+ const controller = new AbortController()
60
+
84
61
  const parser = program
85
62
  .strict()
86
63
  .showHelpOnFail(false, "使用 lzc-cli help 查看更多帮助")
87
- .middleware([setLoggerLevel])
64
+ .middleware([setLoggerLevel, checkLatestVersion(controller)])
88
65
  .parse()
89
66
 
90
- const argv = await parser
91
- if (argv._.length == 1) {
92
- switch (argv._[0]) {
93
- case "box":
94
- case "app":
95
- case "project":
96
- case "appstore":
97
- case "config":
98
- program.showHelp()
99
- return
67
+ try {
68
+ const argv = await parser
69
+ if (argv._.length == 1) {
70
+ switch (argv._[0]) {
71
+ case "box":
72
+ case "app":
73
+ case "project":
74
+ case "appstore":
75
+ case "config":
76
+ program.showHelp()
77
+ return
78
+ }
79
+ } else if (argv._.length == 0) {
80
+ program.showHelp()
100
81
  }
101
- } else if (argv._.length == 0) {
102
- program.showHelp()
82
+ } finally {
83
+ controller.abort()
103
84
  }
104
85
  })()
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import process from "process"
3
+ import logger from "loglevel"
4
+ import yargs from "yargs"
5
+ import { hideBin } from "yargs/helpers"
6
+
7
+ import "../lib/log.js"
8
+ import { pkgInfo } from "../lib/utils.js"
9
+ import { singleLzcDockerComposeCommand } from "../lib/docker/index.js"
10
+
11
+ function setLoggerLevel({ log }) {
12
+ logger.setLevel(log, false)
13
+ }
14
+
15
+ const program = yargs(hideBin(process.argv))
16
+ .scriptName("lzc-docker-compose")
17
+ .usage("<command> [options]")
18
+ .version(`lzc-docker-compose ${pkgInfo.version}`)
19
+ .option("log", {
20
+ type: "string",
21
+ default: "info",
22
+ describe: "log level 'trace', 'debug', 'info', 'warn', 'error'"
23
+ })
24
+ .option("help", {
25
+ alias: "h",
26
+ type: "boolean",
27
+ default: false
28
+ })
29
+ .command(singleLzcDockerComposeCommand("$0"))
30
+
31
+ // 当没有参数的时候,默认显示帮助。
32
+ ;(async () => {
33
+ const parser = program
34
+ .strict(false)
35
+ .showHelpOnFail(false, "使用 lzc-cli help 查看更多帮助")
36
+ .middleware([setLoggerLevel])
37
+ .parse()
38
+
39
+ const argv = await parser
40
+ if (argv._.length == 0) {
41
+ program.showHelp()
42
+ }
43
+ })()
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import process from "process"
3
+ import logger from "loglevel"
4
+ import yargs from "yargs"
5
+ import { hideBin } from "yargs/helpers"
6
+
7
+ import "../lib/log.js"
8
+ import { pkgInfo } from "../lib/utils.js"
9
+ import { singleLzcDockerCommand } from "../lib/docker/index.js"
10
+
11
+ function setLoggerLevel({ log }) {
12
+ logger.setLevel(log, false)
13
+ }
14
+
15
+ const program = yargs(hideBin(process.argv))
16
+ .scriptName("lzc-docker")
17
+ .usage("<command> [options]")
18
+ .version(`lzc-docker ${pkgInfo.version}`)
19
+ .option("log", {
20
+ type: "string",
21
+ default: "info",
22
+ describe: "log level 'trace', 'debug', 'info', 'warn', 'error'"
23
+ })
24
+ .option("help", {
25
+ alias: "h",
26
+ type: "boolean",
27
+ default: false
28
+ })
29
+ .command(singleLzcDockerCommand("$0"))
30
+
31
+ // 当没有参数的时候,默认显示帮助。
32
+ ;(async () => {
33
+ const parser = program
34
+ .strict(false)
35
+ .showHelpOnFail(false, "使用 lzc-cli help 查看更多帮助")
36
+ .middleware([setLoggerLevel])
37
+ .parse()
38
+
39
+ const argv = await parser
40
+ if (argv._.length == 0) {
41
+ program.showHelp()
42
+ }
43
+ })()
@@ -1,13 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
- # 设置 lzcapp 环境变量
4
- # 从1号进程读取环境变量
5
- cat > /tmp/lzcapp_env.sh << EOF
6
- #!/bin/sh
7
- $(/usr/lib/debug.bridge/busybox tr '\0' '\n' < /proc/1/environ | /usr/lib/debug.bridge/busybox xargs -I{} echo 'export "{}"')
8
- EOF
9
- . /tmp/lzcapp_env.sh
10
-
11
3
  # 执行 setupscript 脚本
12
4
  SETUPSCRIPT=/lzcapp/pkg/content/devshell/setupscript
13
5
  if [ -f $SETUPSCRIPT ];then
@@ -1,43 +1,4 @@
1
1
  #!/bin/sh
2
2
  set -e
3
3
 
4
- DEBUG_BRIDGE_LZCAPP=http://app.cloud.lazycat.developer.tools.lzcapp
5
-
6
- mkdir -p /usr/lib/debug.bridge/
7
- # 不能直接对 pkg content 中的 busybox chmod(Read-Only权限)
8
- LZCBUSYBOX=/usr/lib/debug.bridge/busybox
9
- cp /lzcapp/pkg/content/devshell/busybox ${LZCBUSYBOX}
10
- chmod +x ${LZCBUSYBOX}
11
-
12
- mkdir -p /root/.ssh
13
- mkdir -p /etc/debug.bridge
14
-
15
- if ! [ -f /usr/bin/dropbearmulti ]; then
16
- ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/dropbearmulti -O /usr/bin/dropbearmulti
17
- chmod +x /usr/bin/dropbearmulti
18
- fi
19
-
20
- if ! [ -f /usr/bin/rsync ]; then
21
- ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/rsync -O /usr/bin/rsync
22
- chmod +x /usr/bin/rsync
23
- fi
24
-
25
- ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/authorized_keys -O /root/.ssh/authorized_keys
26
- chmod 0644 /root/.ssh/authorized_keys
27
-
28
- ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/bannerfile -O /etc/debug.bridge/bannerfile
29
-
30
- if ${LZCBUSYBOX} netstat -tln | grep ':22222' >/dev/null; then
31
- echo "端口22222正在监听"
32
- ${LZCBUSYBOX} sleep infinity
33
- else
34
- echo "启动 rsync daemon."
35
- rsync --daemon --no-detach --config=/lzcapp/pkg/content/devshell/rsyncd.conf &
36
- while ! ${LZCBUSYBOX} nc -z localhost 873; do
37
- sleep 1
38
- done
39
- echo "rsync daemon 已成功监听 873 端口"
40
-
41
- mkdir -p /etc/dropbear
42
- exec dropbearmulti dropbear -R -F -E -B -p 22222
43
- fi
4
+ echo "init don't nothing..."
@@ -18,6 +18,9 @@ pkgout: ./
18
18
  # icon 仅仅允许 png 后缀的文件
19
19
  icon: ./lazycat.png
20
20
 
21
+ # deploy_params 指定用户运行时输入的模板字段
22
+ # deploy_params: ./lzc-deploy-params.yml
23
+
21
24
  # devshell 自定义应用的开发容器环境
22
25
  # - routers 指定应用容器的访问路由
23
26