@lazycatcloud/lzc-cli 1.2.39 → 1.2.41

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.
@@ -6,12 +6,22 @@ import {
6
6
  isTraceMode,
7
7
  resolveDomain,
8
8
  sleep,
9
- findSshPublicKey
9
+ findSshPublicKey,
10
+ isWindows,
11
+ contextDirname
10
12
  } from "../utils.js"
11
13
  import logger from "loglevel"
12
14
  import commandExists from "command-exists"
15
+ import path from "node:path"
13
16
 
14
- function sshCmdArgs(...args) {
17
+ export function sshBinary() {
18
+ if (isWindows) {
19
+ return "ssh"
20
+ }
21
+ return "ssh"
22
+ }
23
+
24
+ export function sshCmdArgs(...args) {
15
25
  const defaultOptions = [
16
26
  `-o "StrictHostKeyChecking=no"`,
17
27
  `-o "UserKnownHostsFile=/dev/null"`,
@@ -19,7 +29,7 @@ function sshCmdArgs(...args) {
19
29
  "-p 22222",
20
30
  `${isTraceMode() ? "-v" : ""}`
21
31
  ]
22
- return [...defaultOptions, ...args].join(" ")
32
+ return [...defaultOptions, ...args]
23
33
  }
24
34
 
25
35
  export class DebugBridge {
@@ -55,9 +65,9 @@ export class DebugBridge {
55
65
  const stream = fs.createReadStream(lpkPath)
56
66
  const resolvedIp = await resolveDomain(this.domain)
57
67
  const ssh = spawn(
58
- "ssh",
68
+ sshBinary(),
59
69
  [
60
- sshCmdArgs(`box@${resolvedIp}`),
70
+ ...sshCmdArgs(`box@${resolvedIp}`),
61
71
  `install --uid ${this.uid} --pkgId ${pkgId}`
62
72
  ],
63
73
  {
@@ -87,8 +97,8 @@ export class DebugBridge {
87
97
 
88
98
  // 将当前机器上的ssh public key 写到开发者工具中去,并过滤到重复的,管道在执行前会被清空,需要使用一个中间文件
89
99
  const stream = spawn.sync(
90
- "ssh",
91
- [sshCmdArgs(`box@${resolvedIp}`), `add-ssh-public-key`],
100
+ sshBinary(),
101
+ [...sshCmdArgs(`box@${resolvedIp}`), `add-ssh-public-key`],
92
102
  {
93
103
  input: sshInfo.content.trimLeft(),
94
104
  shell: true,
@@ -107,16 +117,16 @@ export class DebugBridge {
107
117
  }
108
118
 
109
119
  async status(appId) {
110
- return this.common("ssh", [
111
- sshCmdArgs(`box@${this.domain}`),
120
+ return this.common(sshBinary(), [
121
+ ...sshCmdArgs(`box@${this.domain}`),
112
122
  `status --uid ${this.uid}`,
113
123
  appId
114
124
  ])
115
125
  }
116
126
 
117
127
  async isDevshell(appId) {
118
- const stdout = await this.common("ssh", [
119
- sshCmdArgs(`box@${this.domain}`),
128
+ const stdout = await this.common(sshBinary(), [
129
+ ...sshCmdArgs(`box@${this.domain}`),
120
130
  `isDevshell --uid ${this.uid}`,
121
131
  appId
122
132
  ])
@@ -124,16 +134,16 @@ export class DebugBridge {
124
134
  }
125
135
 
126
136
  async resume(appId) {
127
- return this.common("ssh", [
128
- sshCmdArgs(`box@${this.domain}`),
137
+ return this.common(sshBinary(), [
138
+ ...sshCmdArgs(`box@${this.domain}`),
129
139
  `resume --uid ${this.uid}`,
130
140
  appId
131
141
  ])
132
142
  }
133
143
 
134
144
  async uninstall(appId) {
135
- return this.common("ssh", [
136
- sshCmdArgs(`box@${this.domain}`),
145
+ return this.common(sshBinary(), [
146
+ ...sshCmdArgs(`box@${this.domain}`),
137
147
  `uninstall --uid ${this.uid}`,
138
148
  appId
139
149
  ])
@@ -153,14 +163,15 @@ export class DebugBridge {
153
163
  const resolvedIp = await resolveDomain(this.domain)
154
164
 
155
165
  const stream = spawn(
156
- "ssh",
166
+ sshBinary(),
157
167
  [
158
- sshCmdArgs(`box@${resolvedIp}`),
168
+ ...sshCmdArgs(`box@${resolvedIp}`),
159
169
  "-t",
160
170
  "devshell",
161
171
  `--uid ${this.uid}`,
162
172
  isUserApp ? "--userapp" : "",
163
173
  appId,
174
+ "/bin/sh",
164
175
  "/lzcapp/pkg/content/devshell/exec.sh"
165
176
  ],
166
177
  {
@@ -185,17 +196,17 @@ export class DebugBridge {
185
196
  const resolvedIp = await resolveDomain(this.domain)
186
197
  const stream = fs.createReadStream(contextTar)
187
198
 
188
- const ssh = spawn(
189
- "ssh",
190
- [sshCmdArgs(`box@${resolvedIp}`), `build --tag ${tag}`],
199
+ const buildStream = spawn(
200
+ sshBinary(),
201
+ [...sshCmdArgs(`box@${resolvedIp}`), `build --tag ${tag}`],
191
202
  {
192
203
  shell: true,
193
204
  stdio: ["pipe", "inherit", "inherit"]
194
205
  }
195
206
  )
196
- stream.pipe(ssh.stdin)
207
+ stream.pipe(buildStream.stdin)
197
208
  return new Promise((resolve, reject) => {
198
- ssh.on("close", (code) => {
209
+ buildStream.on("close", (code) => {
199
210
  code == 0
200
211
  ? resolve(`dev.${this.boxname}.heiyu.space/${tag}`)
201
212
  : reject("在盒子中构建 image 失败")
@@ -2,7 +2,6 @@
2
2
  import path from "node:path"
3
3
  import fs from "node:fs"
4
4
  import logger from "loglevel"
5
- // import { execSync } from "node:child_process"
6
5
  import spawn from "cross-spawn"
7
6
  import { LpkInstaller } from "./lpk_installer.js"
8
7
  import debounce from "lodash.debounce"
@@ -19,7 +18,6 @@ import {
19
18
  isUserApp,
20
19
  createTemplateFileCommon,
21
20
  isDebugMode,
22
- isTraceMode,
23
21
  resolveDomain,
24
22
  isWindows,
25
23
  isMacOs,
@@ -157,36 +155,60 @@ export class AppDevShell {
157
155
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
158
156
  const busyboxPath = path.join(
159
157
  contextDirname(import.meta.url),
160
- "../../template/_lpk/busybox-1.35.0"
158
+ "..",
159
+ "..",
160
+ "template",
161
+ "_lpk",
162
+ "busybox-1.35.0"
161
163
  )
162
164
  let dest = path.join(contentdir, "devshell", "busybox")
163
165
  ensureDir(dest)
164
166
  fs.copyFileSync(busyboxPath, dest)
165
- fs.chmodSync(dest, 0o775)
166
167
  })
167
168
 
168
169
  // 复制 init_debug_bridge.sh 到 devshell 中去
169
170
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
170
171
  const initPath = path.join(
171
172
  contextDirname(import.meta.url),
172
- "../../template/_lpk/init_debug_bridge.sh"
173
+ "..",
174
+ "..",
175
+ "template",
176
+ "_lpk",
177
+ "init_debug_bridge.sh"
173
178
  )
174
179
  let dest = path.join(contentdir, "devshell", "init_debug_bridge.sh")
175
180
  ensureDir(dest)
176
181
  fs.copyFileSync(initPath, dest)
177
- fs.chmodSync(dest, 0o775)
178
182
  })
179
183
 
180
184
  // 复制 exec.sh 到 devshell 中去
181
185
  this.lpkBuild.onBeforeTarContent(async (contentdir) => {
182
186
  const execScriptPath = path.join(
183
187
  contextDirname(import.meta.url),
184
- "../../template/_lpk/exec.sh"
188
+ "..",
189
+ "..",
190
+ "template",
191
+ "_lpk",
192
+ "exec.sh"
185
193
  )
186
194
  let dest = path.join(contentdir, "devshell", "exec.sh")
187
195
  ensureDir(dest)
188
196
  fs.copyFileSync(execScriptPath, dest)
189
- fs.chmodSync(dest, 0o775)
197
+ })
198
+
199
+ // 复制 rsyncd.conf 到 devshell 中去
200
+ this.lpkBuild.onBeforeTarContent(async (contentdir) => {
201
+ const execScriptPath = path.join(
202
+ contextDirname(import.meta.url),
203
+ "..",
204
+ "..",
205
+ "template",
206
+ "_lpk",
207
+ "rsyncd.conf"
208
+ )
209
+ let dest = path.join(contentdir, "devshell", "rsyncd.conf")
210
+ ensureDir(dest)
211
+ fs.copyFileSync(execScriptPath, dest)
190
212
  })
191
213
 
192
214
  // 复制 setupscript 脚本
@@ -207,7 +229,6 @@ export class AppDevShell {
207
229
  } else {
208
230
  fs.writeFileSync(dest, `#!/bin/sh\nset -ex\n${devshell["setupscript"]}`)
209
231
  }
210
- fs.chmodSync(dest, 0o775)
211
232
  })
212
233
 
213
234
  // 在生成 manifest.yml 之前合并 devshell manifest 模板字段
@@ -219,9 +240,10 @@ export class AppDevShell {
219
240
  logger.debug("options devshell delete 'routes' field")
220
241
  delete options["devshell"]["routes"]
221
242
 
222
- // 添加 devshell 必要路由
243
+ // 添加 devshell 必要路由,这里需要使用 /bin/sh 启动后面的脚本,因为在
244
+ // Windows 上打包的文件将会丢失可执行权限
223
245
  routes.push(
224
- "/__debug.bridge=exec://80,/lzcapp/pkg/content/devshell/init_debug_bridge.sh"
246
+ "/__debug.bridge=exec://80,/bin/sh /lzcapp/pkg/content/devshell/init_debug_bridge.sh"
225
247
  )
226
248
  routes.push("/__isdevshell=file:///lzcapp/pkg/devshell")
227
249
 
@@ -286,7 +308,11 @@ export class AppDevShell {
286
308
  try {
287
309
  const dockerfilePath = path.join(
288
310
  contextDirname(import.meta.url),
289
- "../../template/_lpk/Dockerfile.in"
311
+ "..",
312
+ "..",
313
+ "template",
314
+ "_lpk",
315
+ "Dockerfile.in"
290
316
  )
291
317
  await createTemplateFileCommon(
292
318
  dockerfilePath,
@@ -418,25 +444,6 @@ class DevShell {
418
444
  }
419
445
 
420
446
  async syncProject(appId) {
421
- // prettier-ignore
422
- const resolvedIp = await resolveDomain(`dev.${shellApi.boxname}.heiyu.space`);
423
- let rsh = [
424
- "ssh",
425
- "-o",
426
- `"ProxyCommand ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q -W %h:%p -p 22222 box@${resolvedIp}"`,
427
- "-p",
428
- `22222`,
429
- "-o",
430
- `"StrictHostKeyChecking=no"`,
431
- "-o",
432
- `"UserKnownHostsFile=/dev/null"`,
433
- "-o",
434
- `"ConnectionAttempts=3"`,
435
- "-o",
436
- `"ConnectTimeout=30"`,
437
- "-o",
438
- `${isTraceMode() ? '"LogLevel=DEBUG"' : '"LogLevel=ERROR"'}`
439
- ].join(" ")
440
447
  if (isLinux || isMacOs) {
441
448
  // 检查rsync工具是否存在:提示用户
442
449
  const rsyncExisted = commandExists.sync("rsync")
@@ -446,22 +453,29 @@ class DevShell {
446
453
  }
447
454
  }
448
455
 
456
+ const resolvedIp = await resolveDomain(
457
+ `dev.${shellApi.boxname}.heiyu.space`
458
+ )
449
459
  const rsyncDebug = isDebugMode() ? "-P" : ""
450
460
  const host = this.isUserApp
451
461
  ? `${shellApi.uid}.app.${appId}.lzcapp`
452
462
  : `app.${appId}.lzcapp`
453
- const dest = `root@${host}:/lzcapp/cache/devshell`
463
+ const dest = `rsync://${host}@[${resolvedIp}]:873/lzcapp/cache/devshell`
454
464
  const rsyncCmd = isWindows
455
465
  ? path.join(
456
466
  contextDirname(import.meta.url),
457
- "../../template/_lpk/win-rsync/rsync.exe"
467
+ "..",
468
+ "..",
469
+ "template",
470
+ "_lpk",
471
+ "win-rsync",
472
+ "rsync.exe"
458
473
  )
459
474
  : `rsync`
460
475
 
461
476
  try {
462
477
  const rsyncArgs = [
463
478
  `${rsyncDebug}`,
464
- `--rsh='${rsh}'`,
465
479
  `--recursive`,
466
480
  `--relative`,
467
481
  `--perms`,
@@ -472,6 +486,7 @@ class DevShell {
472
486
  ]
473
487
  logger.debug("同步代码: ", rsyncCmd, rsyncArgs.join(" "))
474
488
  const rsyncStream = spawn.sync(rsyncCmd, rsyncArgs, {
489
+ env: { RSYNC_PASSWORD: "fakefakefake" },
475
490
  shell: true,
476
491
  stdio: ["ignore", isDebugMode() ? "inherit" : "ignore", "inherit"]
477
492
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.39",
3
+ "version": "1.2.41",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "files": [
6
6
  "template",
@@ -20,6 +20,7 @@
20
20
  "@balena/dockerignore": "^1.0.2",
21
21
  "@grpc/grpc-js": "^1.11.1",
22
22
  "@grpc/proto-loader": "^0.7.13",
23
+ "@lazycatcloud/sdk": "^0.1.423",
23
24
  "adm-zip": "^0.5.16",
24
25
  "archiver": "^7.0.1",
25
26
  "axios": "^1.7.7",
File without changes
@@ -4,7 +4,7 @@
4
4
  # 从1号进程读取环境变量
5
5
  cat > /tmp/lzcapp_env.sh << EOF
6
6
  #!/bin/sh
7
- $(/lzcapp/pkg/content/devshell/busybox tr '\0' '\n' < /proc/1/environ | /lzcapp/pkg/content/devshell/busybox xargs -I{} echo export {})
7
+ $(/usr/lib/debug.bridge/busybox tr '\0' '\n' < /proc/1/environ | /usr/lib/debug.bridge/busybox xargs -I{} echo export {})
8
8
  EOF
9
9
  . /tmp/lzcapp_env.sh
10
10
 
@@ -2,30 +2,38 @@
2
2
  set -e
3
3
 
4
4
  DEBUG_BRIDGE_LZCAPP=http://app.cloud.lazycat.developer.tools.lzcapp
5
- BUSYBOX=/lzcapp/pkg/content/devshell/busybox
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}
6
11
 
7
12
  mkdir -p /root/.ssh
8
13
  mkdir -p /etc/debug.bridge
9
14
 
10
15
  if ! [ -f /usr/bin/dropbearmulti ]; then
11
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/dropbearmulti -O /usr/bin/dropbearmulti
16
+ ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/dropbearmulti -O /usr/bin/dropbearmulti
12
17
  chmod +x /usr/bin/dropbearmulti
13
18
  fi
14
19
 
15
20
  if ! [ -f /usr/bin/rsync ]; then
16
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/rsync -O /usr/bin/rsync
21
+ ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/rsync -O /usr/bin/rsync
17
22
  chmod +x /usr/bin/rsync
18
23
  fi
19
24
 
20
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/authorized_keys -O /root/.ssh/authorized_keys
25
+ ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/authorized_keys -O /root/.ssh/authorized_keys
21
26
  chmod 0644 /root/.ssh/authorized_keys
22
27
 
23
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/bannerfile -O /etc/debug.bridge/bannerfile
28
+ ${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/bannerfile -O /etc/debug.bridge/bannerfile
24
29
 
25
- if ${BUSYBOX} netstat -tln | grep ':22222' >/dev/null; then
30
+ if ${LZCBUSYBOX} netstat -tln | grep ':22222' >/dev/null; then
26
31
  echo "端口22222正在监听"
27
- ${BUSYBOX} sleep infinity
32
+ ${LZCBUSYBOX} sleep infinity
28
33
  else
34
+ echo "启动 rsync daemon."
35
+ rsync --daemon --no-detach --config=/lzcapp/pkg/content/devshell/rsyncd.conf &
36
+
29
37
  mkdir -p /etc/dropbear
30
38
  exec dropbearmulti dropbear -R -F -E -B -p 22222
31
39
  fi
@@ -0,0 +1,28 @@
1
+ # 全局参数
2
+ uid = root
3
+ gid = root
4
+ use chroot = no
5
+ max connections = 4
6
+ timeout = 300
7
+ pid file = /var/run/rsyncd.pid
8
+ lock file = /var/run/rsync.lock
9
+
10
+ # 实时输出设置
11
+ log file = /dev/stdout
12
+ transfer logging = yes
13
+ log format = %t rsync [%p] %o %h [%a] %m %f %l
14
+
15
+ [lzcapp]
16
+ path = /lzcapp
17
+ read only = no
18
+ dont compress = *.gz *.bz2 *.zip
19
+
20
+ [root]
21
+ path = /root/
22
+ read only = no
23
+ dont compress = *.gz *.bz2 *.zip
24
+
25
+ [tmp]
26
+ path = /tmp/
27
+ read only = no
28
+ dont compress = *.gz *.bz2 *.zip