@lazycatcloud/lzc-cli 1.2.39 → 1.2.42
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/lpk_build.js +5 -0
- package/lib/app/lpk_create.js +10 -2
- package/lib/app/lpk_create_generator.js +17 -5
- package/lib/app/lpk_debug_bridge.js +33 -22
- package/lib/app/lpk_devshell.js +49 -34
- package/lib/app/lpk_installer.js +5 -1
- package/lib/appstore/prePublish.js +4 -33
- package/lib/appstore/publish.js +6 -6
- package/lib/utils.js +13 -3
- package/package.json +2 -1
- package/template/_lpk/busybox-1.35.0 +0 -0
- package/template/_lpk/exec.sh +1 -1
- package/template/_lpk/init_debug_bridge.sh +15 -7
- package/template/_lpk/rsyncd.conf +28 -0
- package/template/lite/_gitignore +4 -0
- package/template/vue/_gitignore +25 -0
package/lib/app/lpk_build.js
CHANGED
|
@@ -187,6 +187,11 @@ export class LpkBuild {
|
|
|
187
187
|
if (!isValidPackageName(this.manifest["package"])) {
|
|
188
188
|
throw `${this.manifest["package"]} 含有非法字符,请使用正确的包名格式(java的包名格式),如:cloud.lazycat.apps.video`
|
|
189
189
|
}
|
|
190
|
+
|
|
191
|
+
if (!this.manifest["application"]["subdomain"]) {
|
|
192
|
+
throw `application 模块下的 subdomain 字段不能为空`
|
|
193
|
+
}
|
|
194
|
+
|
|
190
195
|
return this.manifest
|
|
191
196
|
}
|
|
192
197
|
|
package/lib/app/lpk_create.js
CHANGED
|
@@ -28,7 +28,11 @@ export class LpkManifest {
|
|
|
28
28
|
if (!manifestFilePath) {
|
|
29
29
|
manifestFilePath = path.join(
|
|
30
30
|
this.pwd,
|
|
31
|
-
"
|
|
31
|
+
"..",
|
|
32
|
+
"..",
|
|
33
|
+
"template",
|
|
34
|
+
"_lpk",
|
|
35
|
+
"manifest.yml.in"
|
|
32
36
|
)
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -88,7 +92,11 @@ export class TemplateInit {
|
|
|
88
92
|
// 优先使用模板项目自定义的模板文件
|
|
89
93
|
const typeTemplatePath = path.join(
|
|
90
94
|
contextDirname(import.meta.url),
|
|
91
|
-
|
|
95
|
+
"..",
|
|
96
|
+
"..",
|
|
97
|
+
"template",
|
|
98
|
+
"_lpk",
|
|
99
|
+
`${this.type}.manifest.yml.in`
|
|
92
100
|
)
|
|
93
101
|
const templatePath = isFileExist(typeTemplatePath) ? typeTemplatePath : ""
|
|
94
102
|
await this.lpkManifest.init(templatePath, true)
|
|
@@ -10,10 +10,10 @@ import logger from "loglevel"
|
|
|
10
10
|
const __dirname = contextDirname(import.meta.url)
|
|
11
11
|
|
|
12
12
|
async function loadFiles(dirPath, prefix = "") {
|
|
13
|
-
const templateRoot = path.join(__dirname, "
|
|
13
|
+
const templateRoot = path.join(__dirname, "..", "..", "template")
|
|
14
14
|
const templateDir = path.join(templateRoot, dirPath)
|
|
15
15
|
|
|
16
|
-
const _files = await glob(["**/*"], { cwd: templateDir })
|
|
16
|
+
const _files = await glob(["**/*", "**/.*", ".*"], { cwd: templateDir })
|
|
17
17
|
let content
|
|
18
18
|
let files = {}
|
|
19
19
|
for (let p of _files) {
|
|
@@ -59,7 +59,11 @@ function appendREADME(dir) {
|
|
|
59
59
|
const readme = path.resolve(dir, "README.md")
|
|
60
60
|
const readmeTemplate = path.resolve(
|
|
61
61
|
__dirname,
|
|
62
|
-
"
|
|
62
|
+
"..",
|
|
63
|
+
"..",
|
|
64
|
+
"template",
|
|
65
|
+
"_lpk",
|
|
66
|
+
"README.md"
|
|
63
67
|
)
|
|
64
68
|
if (!isFileExist(readme)) {
|
|
65
69
|
fs.copyFileSync(readmeTemplate, readme)
|
|
@@ -85,14 +89,22 @@ function vueTemplate(type) {
|
|
|
85
89
|
|
|
86
90
|
const lzcBuildTemplatePath = path.resolve(
|
|
87
91
|
__dirname,
|
|
88
|
-
|
|
92
|
+
"..",
|
|
93
|
+
"..",
|
|
94
|
+
"template",
|
|
95
|
+
"_lpk",
|
|
96
|
+
"vue.lzc-build.yml.in"
|
|
89
97
|
)
|
|
90
98
|
logger.debug("复制", lzcBuildTemplatePath)
|
|
91
99
|
fs.copyFileSync(lzcBuildTemplatePath, path.resolve(name, "lzc-build.yml"))
|
|
92
100
|
|
|
93
101
|
const iconPngPath = path.resolve(
|
|
94
102
|
__dirname,
|
|
95
|
-
"
|
|
103
|
+
"..",
|
|
104
|
+
"..",
|
|
105
|
+
"template",
|
|
106
|
+
"_lpk",
|
|
107
|
+
"lazycat.png"
|
|
96
108
|
)
|
|
97
109
|
fs.copyFileSync(iconPngPath, path.resolve(name, "lazycat.png"))
|
|
98
110
|
|
|
@@ -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
|
|
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]
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
189
|
-
|
|
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(
|
|
207
|
+
stream.pipe(buildStream.stdin)
|
|
197
208
|
return new Promise((resolve, reject) => {
|
|
198
|
-
|
|
209
|
+
buildStream.on("close", (code) => {
|
|
199
210
|
code == 0
|
|
200
211
|
? resolve(`dev.${this.boxname}.heiyu.space/${tag}`)
|
|
201
212
|
: reject("在盒子中构建 image 失败")
|
package/lib/app/lpk_devshell.js
CHANGED
|
@@ -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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
"
|
|
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 = `
|
|
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
|
-
"
|
|
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/lib/app/lpk_installer.js
CHANGED
|
@@ -93,8 +93,12 @@ export class LpkInstaller {
|
|
|
93
93
|
const tempDir = fs.mkdtempSync(".lzc-cli-install")
|
|
94
94
|
let manifest
|
|
95
95
|
try {
|
|
96
|
-
unzipSync(pkgPath, tempDir)
|
|
96
|
+
unzipSync(pkgPath, tempDir, ["manifest.yml", "icon.png"])
|
|
97
97
|
manifest = loadFromYaml(path.join(tempDir, "manifest.yml"))
|
|
98
|
+
if (!manifest["application"]["subdomain"]) {
|
|
99
|
+
throw "manifest.yml 中的 `application.subdomain` 字段不能为空"
|
|
100
|
+
}
|
|
101
|
+
|
|
98
102
|
logger.debug("是否生成APK:", installConfig.apk)
|
|
99
103
|
if (installConfig.apk) {
|
|
100
104
|
await triggerApk(
|
|
@@ -6,6 +6,7 @@ import inquirer from "inquirer"
|
|
|
6
6
|
import path from "node:path"
|
|
7
7
|
import { isFileExist, isPngWithFile, unzipSync } from "../utils.js"
|
|
8
8
|
import env from "../env.js"
|
|
9
|
+
import { Publish } from "./publish.js"
|
|
9
10
|
|
|
10
11
|
async function askChangeLog() {
|
|
11
12
|
const noEmpty = (value) => value != ""
|
|
@@ -37,36 +38,6 @@ export class PrePublish {
|
|
|
37
38
|
this.baseUrl = baseUrl
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
/**
|
|
41
|
-
* @param {string} raw
|
|
42
|
-
*/
|
|
43
|
-
isJSON(raw) {
|
|
44
|
-
const ml = raw.length
|
|
45
|
-
if (ml <= 1) return false
|
|
46
|
-
return raw[0] == "{" && raw[ml - 1] == "}"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
preCheck(pkgPath) {
|
|
50
|
-
const tempDir = fs.mkdtempSync(".lzc-cli-publish")
|
|
51
|
-
try {
|
|
52
|
-
unzipSync(pkgPath, tempDir)
|
|
53
|
-
if (isFileExist(path.join(tempDir, "devshell"))) {
|
|
54
|
-
logger.error(
|
|
55
|
-
"不能发布一个devshell的版本,请重新使用 `lzc-cli project build` 构建"
|
|
56
|
-
)
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
const tempIcon = path.join(tempDir, "icon.png")
|
|
60
|
-
if (!isFileExist(tempIcon) || !isPngWithFile(tempIcon)) {
|
|
61
|
-
logger.error("icon 必须是 png 格式")
|
|
62
|
-
return false
|
|
63
|
-
}
|
|
64
|
-
return true
|
|
65
|
-
} finally {
|
|
66
|
-
fs.rmSync(tempDir, { recursive: true })
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
41
|
async getDict() {
|
|
71
42
|
const url = this.baseUrl + "/groups/dict"
|
|
72
43
|
const token = env.get("token")
|
|
@@ -77,7 +48,7 @@ export class PrePublish {
|
|
|
77
48
|
}
|
|
78
49
|
})
|
|
79
50
|
const text = (await res.text()).trim()
|
|
80
|
-
if (!
|
|
51
|
+
if (!Publish.isJSON(text)) {
|
|
81
52
|
logger.error(`parse error: dict resp text not is json`)
|
|
82
53
|
return
|
|
83
54
|
}
|
|
@@ -101,7 +72,7 @@ export class PrePublish {
|
|
|
101
72
|
}
|
|
102
73
|
})
|
|
103
74
|
const text = (await res.text()).trim()
|
|
104
|
-
if (!
|
|
75
|
+
if (!Publish.isJSON(text)) {
|
|
105
76
|
logger.error(`parse error: upload resp text not is json`)
|
|
106
77
|
return
|
|
107
78
|
}
|
|
@@ -115,7 +86,7 @@ export class PrePublish {
|
|
|
115
86
|
* @param {string} changelog
|
|
116
87
|
*/
|
|
117
88
|
async publish(pkgPath, changelog, gid) {
|
|
118
|
-
if (!
|
|
89
|
+
if (!Publish.preCheck(pkgPath)) return
|
|
119
90
|
|
|
120
91
|
await autoLogin()
|
|
121
92
|
|
package/lib/appstore/publish.js
CHANGED
|
@@ -26,16 +26,16 @@ export class Publish {
|
|
|
26
26
|
/**
|
|
27
27
|
* @param {string} raw
|
|
28
28
|
*/
|
|
29
|
-
isJSON(raw) {
|
|
29
|
+
static isJSON(raw) {
|
|
30
30
|
const ml = raw.length
|
|
31
31
|
if (ml <= 1) return false
|
|
32
32
|
return raw[0] == "{" && raw[ml - 1] == "}"
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
preCheck(pkgPath) {
|
|
35
|
+
static preCheck(pkgPath) {
|
|
36
36
|
const tempDir = fs.mkdtempSync(".lzc-cli-publish")
|
|
37
37
|
try {
|
|
38
|
-
unzipSync(pkgPath, tempDir)
|
|
38
|
+
unzipSync(pkgPath, tempDir, ["devshell", "icon.png"])
|
|
39
39
|
if (isFileExist(path.join(tempDir, "devshell"))) {
|
|
40
40
|
logger.error(
|
|
41
41
|
"不能发布一个devshell的版本,请重新使用 `lzc-cli project build` 构建"
|
|
@@ -44,7 +44,7 @@ export class Publish {
|
|
|
44
44
|
}
|
|
45
45
|
const tempIcon = path.join(tempDir, "icon.png")
|
|
46
46
|
if (!isFileExist(tempIcon) || !isPngWithFile(tempIcon)) {
|
|
47
|
-
logger.error("icon
|
|
47
|
+
logger.error("icon 必须存在且要求是 png 格式")
|
|
48
48
|
return false
|
|
49
49
|
}
|
|
50
50
|
return true
|
|
@@ -58,7 +58,7 @@ export class Publish {
|
|
|
58
58
|
* @param {string} changelog
|
|
59
59
|
*/
|
|
60
60
|
async publish(pkgPath, changelog) {
|
|
61
|
-
if (!
|
|
61
|
+
if (!Publish.preCheck(pkgPath)) return
|
|
62
62
|
|
|
63
63
|
await autoLogin()
|
|
64
64
|
|
|
@@ -80,7 +80,7 @@ export class Publish {
|
|
|
80
80
|
body: form
|
|
81
81
|
})
|
|
82
82
|
const text = (await res.text()).trim()
|
|
83
|
-
if (!
|
|
83
|
+
if (!Publish.isJSON(text)) {
|
|
84
84
|
logger.info("upload lpk fail", text)
|
|
85
85
|
return
|
|
86
86
|
}
|
package/lib/utils.js
CHANGED
|
@@ -474,14 +474,24 @@ export async function resolveDomain(domain) {
|
|
|
474
474
|
}
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
export function unzipSync(zipPath, destPath) {
|
|
477
|
+
export function unzipSync(zipPath, destPath, entries = []) {
|
|
478
478
|
// 确保目标目录存在
|
|
479
479
|
fs.mkdirSync(destPath, { recursive: true })
|
|
480
480
|
// 创建 zip 实例
|
|
481
481
|
const zip = new AdmZip(zipPath)
|
|
482
482
|
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
if (entries.length > 0) {
|
|
484
|
+
entries.forEach((entry) => {
|
|
485
|
+
try {
|
|
486
|
+
zip.extractEntryTo(entry, destPath, false, true)
|
|
487
|
+
} catch {
|
|
488
|
+
logger.debug(`压缩包中没有找到 ${entry} 文件`)
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
} else {
|
|
492
|
+
// 同步解压所有文件
|
|
493
|
+
zip.extractAllTo(destPath, true)
|
|
494
|
+
}
|
|
485
495
|
}
|
|
486
496
|
|
|
487
497
|
export function findSshPublicKey() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazycatcloud/lzc-cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.42",
|
|
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
|
package/template/_lpk/exec.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# 从1号进程读取环境变量
|
|
5
5
|
cat > /tmp/lzcapp_env.sh << EOF
|
|
6
6
|
#!/bin/sh
|
|
7
|
-
$(/
|
|
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
|
-
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
28
|
+
${LZCBUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/bannerfile -O /etc/debug.bridge/bannerfile
|
|
24
29
|
|
|
25
|
-
if ${
|
|
30
|
+
if ${LZCBUSYBOX} netstat -tln | grep ':22222' >/dev/null; then
|
|
26
31
|
echo "端口22222正在监听"
|
|
27
|
-
${
|
|
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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
node_modules
|
|
3
|
+
dist
|
|
4
|
+
*.lpk
|
|
5
|
+
|
|
6
|
+
# local env files
|
|
7
|
+
.env.local
|
|
8
|
+
.env.*.local
|
|
9
|
+
|
|
10
|
+
# Log files
|
|
11
|
+
npm-debug.log*
|
|
12
|
+
yarn-debug.log*
|
|
13
|
+
yarn-error.log*
|
|
14
|
+
pnpm-debug.log*
|
|
15
|
+
|
|
16
|
+
# Editor directories and files
|
|
17
|
+
.idea
|
|
18
|
+
.vscode
|
|
19
|
+
*.suo
|
|
20
|
+
*.ntvs*
|
|
21
|
+
*.njsproj
|
|
22
|
+
*.sln
|
|
23
|
+
*.sw?
|
|
24
|
+
.temp
|
|
25
|
+
.cache
|