@lazycatcloud/lzc-cli 2.0.0-pre.0 → 2.0.0-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -7
- package/changelog.md +50 -19
- package/lib/app/apkshell.js +7 -44
- package/lib/app/index.js +4 -0
- package/lib/app/lpk_build.js +266 -56
- package/lib/app/lpk_build_images.js +37 -16
- package/lib/app/lpk_create.js +158 -83
- package/lib/app/lpk_create_generator.js +35 -42
- package/lib/app/lpk_installer.js +4 -3
- package/lib/app/manifest_build.js +259 -0
- package/lib/app/project_cp.js +5 -10
- package/lib/app/project_deploy.js +36 -11
- package/lib/app/project_exec.js +48 -11
- package/lib/app/project_info.js +59 -59
- package/lib/app/project_log.js +5 -10
- package/lib/app/project_runtime.js +113 -18
- package/lib/app/project_start.js +6 -11
- package/lib/app/project_sync.js +499 -0
- package/lib/appstore/apkshell.js +50 -0
- package/lib/appstore/publish.js +54 -15
- package/lib/build_remote.js +0 -1
- package/lib/config/index.js +1 -1
- package/lib/debug_bridge.js +81 -21
- package/lib/i18n/locales/en/translation.json +262 -262
- package/lib/i18n/locales/zh/translation.json +262 -262
- package/lib/lpk/core.js +2 -1
- package/lib/migrate/index.js +52 -0
- package/lib/package_info.js +135 -0
- package/lib/shellapi.js +35 -1
- package/lib/sig/core.js +2 -2
- package/lib/utils.js +91 -14
- package/package.json +89 -89
- package/scripts/cli.js +2 -0
- package/scripts/smoke/frontend-dev-entry.mjs +104 -0
- package/scripts/smoke/template-project.mjs +311 -0
- package/template/_lpk/README.md +6 -3
- package/template/_lpk/gui-vnc.manifest.yml.in +0 -9
- package/template/_lpk/hello-vue.manifest.yml.in +38 -0
- package/template/_lpk/manifest.yml.in +0 -9
- package/template/_lpk/package.yml.in +7 -0
- package/template/_lpk/todolist-golang.manifest.yml.in +23 -9
- package/template/_lpk/todolist-java.manifest.yml.in +23 -9
- package/template/_lpk/todolist-python.manifest.yml.in +31 -9
- package/template/_lpk/todolist-serverless.manifest.yml.in +38 -0
- package/template/blank/lzc-build.dev.yml +4 -0
- package/template/blank/lzc-build.yml +0 -2
- package/template/blank/lzc-manifest.yml +3 -12
- package/template/blank/package.yml +7 -0
- package/template/golang/Dockerfile +1 -1
- package/template/golang/Dockerfile.dev +20 -0
- package/template/golang/README.md +22 -11
- package/template/golang/_lzcdevignore +21 -0
- package/template/golang/lzc-build.dev.yml +12 -0
- package/template/golang/lzc-build.yml +0 -5
- package/template/golang/main.go +1 -1
- package/template/golang/manifest.dev.page.js +24 -0
- package/template/golang/run.sh +7 -0
- package/template/gui-vnc/README.md +5 -1
- package/template/gui-vnc/lzc-build.dev.yml +4 -0
- package/template/gui-vnc/lzc-build.yml +0 -5
- package/template/python/Dockerfile +2 -2
- package/template/python/Dockerfile.dev +18 -0
- package/template/python/README.md +28 -11
- package/template/python/_lzcdevignore +21 -0
- package/template/python/app.py +1 -1
- package/template/python/lzc-build.dev.yml +12 -0
- package/template/python/lzc-build.yml +0 -5
- package/template/python/manifest.dev.page.js +25 -0
- package/template/python/run.sh +12 -1
- package/template/springboot/Dockerfile +1 -1
- package/template/springboot/Dockerfile.dev +20 -0
- package/template/springboot/README.md +22 -11
- package/template/springboot/_lzcdevignore +21 -0
- package/template/springboot/lzc-build.dev.yml +12 -0
- package/template/springboot/lzc-build.yml +0 -5
- package/template/springboot/manifest.dev.page.js +24 -0
- package/template/springboot/run.sh +7 -0
- package/template/vue/README.md +14 -27
- package/template/vue/_gitignore +0 -1
- package/template/vue/lzc-build.dev.yml +7 -0
- package/template/vue/lzc-build.yml +0 -2
- package/template/vue/manifest.dev.page.js +50 -0
- package/template/vue-minidb/README.md +11 -19
- package/template/vue-minidb/_gitignore +0 -1
- package/template/vue-minidb/lzc-build.dev.yml +7 -0
- package/template/vue-minidb/lzc-build.yml +0 -2
- package/template/vue-minidb/manifest.dev.page.js +50 -0
- package/template/blank/_gitignore +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Blob } from 'node:buffer';
|
|
4
|
+
import logger from 'loglevel';
|
|
5
|
+
import fetch, { FormData } from 'node-fetch';
|
|
6
|
+
import { t } from '../i18n/index.js';
|
|
7
|
+
import { appStoreServerUrl } from './env.js';
|
|
8
|
+
|
|
9
|
+
// axios@1.7.7 依赖的 form-data 使用了 util.isArray 导致 node 会输出弃用警告 (所以将逻辑迁移避免依赖)
|
|
10
|
+
export async function triggerApk(id, name, iconPath) {
|
|
11
|
+
if (!id) {
|
|
12
|
+
logger.error(t('lzc_cli.lib.appstore.apkshell.trigger_apk_empty_appid', 'Appid 为必填项!'));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const appName = name || t('lzc_cli.lib.appstore.apkshell.trigger_apk_default_app_name', '懒猫应用');
|
|
17
|
+
const form = new FormData();
|
|
18
|
+
form.append('app_id', id);
|
|
19
|
+
form.append('app_name', appName);
|
|
20
|
+
|
|
21
|
+
if (iconPath && fs.existsSync(iconPath)) {
|
|
22
|
+
const iconBuffer = fs.readFileSync(iconPath);
|
|
23
|
+
form.append('app_icon', new Blob([iconBuffer]), path.basename(iconPath));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const controller = new AbortController();
|
|
27
|
+
const timer = setTimeout(() => controller.abort(), 5000);
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const resp = await fetch(`${appStoreServerUrl}/api/trigger_latest_for_app`, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
body: form,
|
|
33
|
+
signal: controller.signal,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
logger.debug('triggerApk resp:', resp);
|
|
37
|
+
if (resp.status == 304) {
|
|
38
|
+
logger.debug(t('lzc_cli.lib.appstore.apkshell.trigger_apk_build_tips', `APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`));
|
|
39
|
+
} else if (resp.status <= 201) {
|
|
40
|
+
logger.info(t('lzc_cli.lib.appstore.apkshell.trigger_apk_build_ok_tips', `APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`));
|
|
41
|
+
} else if (resp.status >= 400) {
|
|
42
|
+
logger.debug(t('lzc_cli.lib.appstore.apkshell.trigger_apk_build_failed', '请求按钮应用出错:'), await resp.text());
|
|
43
|
+
throw t('lzc_cli.lib.appstore.apkshell.trigger_apk_build_failed_tips', `请求生成应用出错! 使用 --apk=n 停止生成APK`);
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.debug(error);
|
|
47
|
+
} finally {
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
}
|
|
50
|
+
}
|
package/lib/appstore/publish.js
CHANGED
|
@@ -107,15 +107,33 @@ async function askPublishAppInfo(baseUrl, manifest, locale) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
async function askWhetherCreateLPK(baseUrl, manifest, locale) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
try {
|
|
111
|
+
// 是否允许创建应用预检请求
|
|
112
|
+
const _options = await request(`${baseUrl}/app/create`, {
|
|
113
|
+
method: 'OPTIONS',
|
|
114
|
+
});
|
|
115
|
+
logger.debug('create app preflight:', { url: _options.url, ok: _options.ok, status: _options.status });
|
|
116
|
+
if (!_options.ok || _options.status < 199 || _options.status > 299) {
|
|
117
|
+
throw undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 要求输入应用信息
|
|
121
|
+
const answers = await inquirer.prompt([
|
|
122
|
+
{
|
|
123
|
+
name: 'continue',
|
|
124
|
+
type: 'input',
|
|
125
|
+
message: t(
|
|
126
|
+
'lzc_cli.lib.publish.ask_whether_create_lpk_continue_prompt',
|
|
127
|
+
'检测到您当前的应用,还没有在懒猫微服中创建,是否使用当前的安装包中的信息进行创建? [y/n]',
|
|
128
|
+
),
|
|
129
|
+
default: 'y',
|
|
130
|
+
},
|
|
131
|
+
]);
|
|
132
|
+
if (answers.continue.toLowerCase() != 'y') {
|
|
133
|
+
throw undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 发送创建应用请求
|
|
119
137
|
const appInfo = await askPublishAppInfo(baseUrl, manifest, locale);
|
|
120
138
|
const crateAppRes = await request(`${baseUrl}/app/create`, {
|
|
121
139
|
method: 'POST',
|
|
@@ -127,9 +145,28 @@ async function askWhetherCreateLPK(baseUrl, manifest, locale) {
|
|
|
127
145
|
source_author: appInfo.author,
|
|
128
146
|
}),
|
|
129
147
|
});
|
|
130
|
-
logger.debug('create app res:
|
|
131
|
-
|
|
132
|
-
|
|
148
|
+
logger.debug('create app res:', await crateAppRes.text());
|
|
149
|
+
if (!crateAppRes.ok) {
|
|
150
|
+
const data = await crateAppRes.json();
|
|
151
|
+
throw new Error(data?.message || `status:${crateAppRes.status} statusText:${crateAppRes.statusText}`);
|
|
152
|
+
}
|
|
153
|
+
logger.info(
|
|
154
|
+
t('lzc_cli.lib.publish.ask_whether_create_lpk_success_tips', `创建 {{ package }} 应用成功!`, {
|
|
155
|
+
package: manifest['package'],
|
|
156
|
+
interpolation: { escapeValue: false },
|
|
157
|
+
}),
|
|
158
|
+
);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error) {
|
|
161
|
+
logger.debug('create app failed: ', error.message ?? 'unknown');
|
|
162
|
+
logger.error(
|
|
163
|
+
t('lzc_cli.lib.publish.ask_whether_create_lpk_failed_tips', `创建 {{ package }} 应用失败!`, {
|
|
164
|
+
package: manifest['package'],
|
|
165
|
+
interpolation: { escapeValue: false },
|
|
166
|
+
}),
|
|
167
|
+
error.message || '',
|
|
168
|
+
);
|
|
169
|
+
}
|
|
133
170
|
logger.info(
|
|
134
171
|
t(
|
|
135
172
|
'lzc_cli.lib.publish.ask_whether_create_lpk_fail_tips',
|
|
@@ -212,7 +249,7 @@ export class Publish {
|
|
|
212
249
|
|
|
213
250
|
const { manifest, appIdExisted } = await this.checkAppIdExist(pkgPath);
|
|
214
251
|
if (!appIdExisted) {
|
|
215
|
-
await askWhetherCreateLPK(this.baseUrl, manifest,
|
|
252
|
+
await askWhetherCreateLPK(this.baseUrl, manifest, currentLocale);
|
|
216
253
|
}
|
|
217
254
|
|
|
218
255
|
await autoLogin();
|
|
@@ -239,7 +276,7 @@ export class Publish {
|
|
|
239
276
|
logger.error(
|
|
240
277
|
t('lzc_cli.lib.publish.publish_lpk_fail_tips', `LPK 文件上传失败,err: {{ message }}`, {
|
|
241
278
|
message: lpkInfo?.message ?? lpkInfo,
|
|
242
|
-
interpolation: { escapeValue: false }
|
|
279
|
+
interpolation: { escapeValue: false },
|
|
243
280
|
}),
|
|
244
281
|
);
|
|
245
282
|
throw new Error(lpkInfo?.message ?? lpkInfo);
|
|
@@ -253,7 +290,7 @@ export class Publish {
|
|
|
253
290
|
|
|
254
291
|
// changelogs 本地化
|
|
255
292
|
const langKey = getLanguageForLocale(currentLocale);
|
|
256
|
-
changelogs[langKey] = changelog
|
|
293
|
+
changelogs[langKey] = changelog;
|
|
257
294
|
}
|
|
258
295
|
logger.debug('publish changelogs is', changelogs);
|
|
259
296
|
|
|
@@ -270,6 +307,8 @@ export class Publish {
|
|
|
270
307
|
pkg_path: lpkInfo.url,
|
|
271
308
|
unsupported_platforms: lpkInfo.unsupportedPlatforms,
|
|
272
309
|
min_os_version: lpkInfo.minOsVersion,
|
|
310
|
+
lpk_size: lpkInfo.lpkSize,
|
|
311
|
+
image_size: lpkInfo.imageSize,
|
|
273
312
|
changelogs,
|
|
274
313
|
},
|
|
275
314
|
};
|
package/lib/build_remote.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { loadBuildRemoteFromConfig } from './box/ssh_remote.js';
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_BUILD_CONFIG_FILE = 'lzc-build.yml';
|
|
4
|
-
export const DEFAULT_BUILD_BASE_FILE = 'lzc-build.base.yml';
|
|
5
4
|
|
|
6
5
|
export function resolveBuildRemoteFromOptions(options, source = DEFAULT_BUILD_CONFIG_FILE) {
|
|
7
6
|
void options;
|
package/lib/config/index.js
CHANGED
|
@@ -51,7 +51,7 @@ export function configCommand(program) {
|
|
|
51
51
|
];
|
|
52
52
|
program.command({
|
|
53
53
|
command: 'config',
|
|
54
|
-
desc:
|
|
54
|
+
desc: t('lzc_cli.lib.config.index.config_cmd_desc', '配置管理'),
|
|
55
55
|
builder: (args) => {
|
|
56
56
|
args.command(subCommands);
|
|
57
57
|
args.example('$0 config get', t('lzc_cli.lib.config.index.config_cmd_list_tips', '列出所有配置'))
|
package/lib/debug_bridge.js
CHANGED
|
@@ -108,6 +108,21 @@ function normalizeErrorMessage(error) {
|
|
|
108
108
|
return String(error).trim();
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
export function shellEscapeArg(value) {
|
|
112
|
+
const text = String(value ?? '');
|
|
113
|
+
if (text === '') {
|
|
114
|
+
return "''";
|
|
115
|
+
}
|
|
116
|
+
if (/^[A-Za-z0-9_/.:=,@+-]+$/.test(text)) {
|
|
117
|
+
return text;
|
|
118
|
+
}
|
|
119
|
+
return "'" + text.replace(/'/g, "'\\''") + "'";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function buildSSHRemoteCommand(args = []) {
|
|
123
|
+
return args.map((arg) => shellEscapeArg(arg)).join(' ');
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
export class DebugBridge {
|
|
112
127
|
constructor(baseDir = process.cwd(), buildRemote = undefined) {
|
|
113
128
|
this.buildRemote = buildRemote === undefined ? resolveBuildRemoteFromFile(baseDir) : buildRemote;
|
|
@@ -275,6 +290,13 @@ export class DebugBridge {
|
|
|
275
290
|
return args;
|
|
276
291
|
}
|
|
277
292
|
|
|
293
|
+
async resolveDevId() {
|
|
294
|
+
if (this.isBuildRemoteMode()) {
|
|
295
|
+
return '';
|
|
296
|
+
}
|
|
297
|
+
return shellApi.resolveClientId();
|
|
298
|
+
}
|
|
299
|
+
|
|
278
300
|
async init() {
|
|
279
301
|
await this.checkDevTools();
|
|
280
302
|
if (!(await this.canPublicKey())) {
|
|
@@ -484,6 +506,29 @@ export class DebugBridge {
|
|
|
484
506
|
}
|
|
485
507
|
}
|
|
486
508
|
|
|
509
|
+
async syncDevID(appId, devId = '', userApp = false) {
|
|
510
|
+
const normalizedDevId = String(devId ?? '').trim();
|
|
511
|
+
if (this.isBuildRemoteMode()) {
|
|
512
|
+
const commandArgs = await this.remoteCommandWithUID(['sync-dev-id']);
|
|
513
|
+
if (normalizedDevId) {
|
|
514
|
+
commandArgs.push('--dev-id', normalizedDevId);
|
|
515
|
+
}
|
|
516
|
+
if (userApp) {
|
|
517
|
+
commandArgs.push('--userapp');
|
|
518
|
+
}
|
|
519
|
+
commandArgs.push(appId);
|
|
520
|
+
return this.remoteCommon(commandArgs);
|
|
521
|
+
}
|
|
522
|
+
const rawArgs = ['sync-dev-id', `--uid ${this.uid}`];
|
|
523
|
+
if (normalizedDevId) {
|
|
524
|
+
rawArgs.push(`--dev-id ${normalizedDevId}`);
|
|
525
|
+
}
|
|
526
|
+
if (userApp) {
|
|
527
|
+
rawArgs.push('--userapp');
|
|
528
|
+
}
|
|
529
|
+
rawArgs.push(appId);
|
|
530
|
+
return this.common(sshBinary(), [...sshCmdArgs(`box@${this.domain}`), rawArgs.join(' ')]);
|
|
531
|
+
}
|
|
487
532
|
async isDevshell(appId) {
|
|
488
533
|
await this.backendVersion020();
|
|
489
534
|
if (this.isBuildRemoteMode()) {
|
|
@@ -698,15 +743,20 @@ export class DebugBridge {
|
|
|
698
743
|
|
|
699
744
|
async lzcDocker(argv) {
|
|
700
745
|
await this.backendVersion020();
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
746
|
+
let stream;
|
|
747
|
+
if (this.isBuildRemoteMode()) {
|
|
748
|
+
stream = spawn(sshBinary(), this.remoteBridgeArgs(['lzc-docker', ...argv], { tty: true }), {
|
|
749
|
+
shell: false,
|
|
750
|
+
stdio: 'inherit',
|
|
751
|
+
});
|
|
752
|
+
} else {
|
|
753
|
+
const resolvedIp = await resolveDomain(this.domain);
|
|
754
|
+
const remoteCommand = buildSSHRemoteCommand(['lzc-docker', ...argv]);
|
|
755
|
+
stream = spawn(sshBinary(), [...sshCmdArgsRaw(`box@${resolvedIp}`), '-t', remoteCommand], {
|
|
756
|
+
shell: false,
|
|
757
|
+
stdio: 'inherit',
|
|
758
|
+
});
|
|
759
|
+
}
|
|
710
760
|
return new Promise((resolve, reject) => {
|
|
711
761
|
stream.on('close', (code) => {
|
|
712
762
|
code == 0 ? resolve() : reject();
|
|
@@ -911,24 +961,29 @@ export class DebugBridge {
|
|
|
911
961
|
});
|
|
912
962
|
}
|
|
913
963
|
|
|
914
|
-
async lzcDockerCapture(argv) {
|
|
964
|
+
async lzcDockerCapture(argv, options = {}) {
|
|
915
965
|
await this.backendVersion020();
|
|
966
|
+
const stdinText = options && Object.prototype.hasOwnProperty.call(options, 'stdinText') ? String(options.stdinText ?? '') : '';
|
|
916
967
|
let stream;
|
|
917
968
|
if (this.isBuildRemoteMode()) {
|
|
918
969
|
stream = spawn(sshBinary(), this.remoteBridgeArgs(['lzc-docker', ...argv]), {
|
|
919
970
|
shell: false,
|
|
920
|
-
stdio: ['
|
|
971
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
921
972
|
});
|
|
922
973
|
} else {
|
|
923
974
|
const resolvedIp = await resolveDomain(this.domain);
|
|
924
975
|
stream = spawn(sshBinary(), [...sshCmdArgsRaw(`box@${resolvedIp}`), 'lzc-docker', ...argv], {
|
|
925
976
|
shell: false,
|
|
926
|
-
stdio: ['
|
|
977
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
927
978
|
});
|
|
928
979
|
}
|
|
929
980
|
|
|
930
981
|
return await new Promise((resolve, reject) => {
|
|
931
982
|
let output = '';
|
|
983
|
+
if (stdinText) {
|
|
984
|
+
stream.stdin.write(stdinText);
|
|
985
|
+
}
|
|
986
|
+
stream.stdin.end();
|
|
932
987
|
stream.stdout.on('data', (chunk) => {
|
|
933
988
|
output += chunk.toString();
|
|
934
989
|
});
|
|
@@ -1045,15 +1100,20 @@ export class DebugBridge {
|
|
|
1045
1100
|
|
|
1046
1101
|
async lzcDockerCompose(argv) {
|
|
1047
1102
|
await this.backendVersion020();
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1103
|
+
let stream;
|
|
1104
|
+
if (this.isBuildRemoteMode()) {
|
|
1105
|
+
stream = spawn(sshBinary(), this.remoteBridgeArgs(['lzc-docker-compose', ...argv], { tty: true }), {
|
|
1106
|
+
shell: false,
|
|
1107
|
+
stdio: 'inherit',
|
|
1108
|
+
});
|
|
1109
|
+
} else {
|
|
1110
|
+
const resolvedIp = await resolveDomain(this.domain);
|
|
1111
|
+
const remoteCommand = buildSSHRemoteCommand(['lzc-docker-compose', ...argv]);
|
|
1112
|
+
stream = spawn(sshBinary(), [...sshCmdArgsRaw(`box@${resolvedIp}`), '-t', remoteCommand], {
|
|
1113
|
+
shell: false,
|
|
1114
|
+
stdio: 'inherit',
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1057
1117
|
return new Promise((resolve, reject) => {
|
|
1058
1118
|
stream.on('close', (code) => {
|
|
1059
1119
|
code == 0 ? resolve() : reject();
|