@lazycatcloud/lzc-cli 1.3.12 → 1.3.14
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 +21 -0
- package/lib/app/apkshell.js +37 -40
- package/lib/app/index.js +187 -186
- package/lib/app/lpk_build.js +345 -358
- package/lib/app/lpk_create.js +136 -155
- package/lib/app/lpk_create_generator.js +77 -66
- package/lib/app/lpk_devshell.js +444 -533
- package/lib/app/lpk_devshell_docker.js +48 -47
- package/lib/app/lpk_installer.js +120 -123
- package/lib/appstore/index.js +245 -214
- package/lib/appstore/login.js +146 -143
- package/lib/appstore/prePublish.js +101 -100
- package/lib/appstore/publish.js +256 -256
- package/lib/box/index.js +82 -77
- package/lib/config/index.js +59 -54
- package/lib/debug_bridge.js +282 -330
- package/lib/docker/index.js +84 -86
- package/lib/i18n/README.md +25 -0
- package/lib/i18n/index.js +37 -0
- package/lib/i18n/locales/en/translation.json +252 -0
- package/lib/i18n/locales/zh/translation.json +252 -0
- package/lib/shellapi.js +122 -146
- package/lib/utils.js +539 -552
- package/package.json +6 -8
- package/scripts/cli.js +81 -77
- package/scripts/lzc-docker-compose.js +34 -33
- package/scripts/lzc-docker.js +34 -33
|
@@ -1,54 +1,55 @@
|
|
|
1
|
-
import path from
|
|
2
|
-
import fs from
|
|
3
|
-
import { DockerfileParser } from
|
|
4
|
-
import glob from
|
|
5
|
-
import ignore from
|
|
6
|
-
import { tarContentDir } from
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { DockerfileParser } from 'dockerfile-ast';
|
|
4
|
+
import glob from 'fast-glob';
|
|
5
|
+
import ignore from '@balena/dockerignore';
|
|
6
|
+
import { tarContentDir } from '../utils.js';
|
|
7
|
+
import { t } from '../i18n/index.js';
|
|
7
8
|
|
|
8
9
|
export async function collectContextFromDockerFile(contextDir, dockerfilePath) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
if (!fs.existsSync(dockerfilePath)) {
|
|
11
|
+
throw t('lzc_cli.lib.app.lpk_devshell_docker.not_exists_dockerfile_fail', '未发现 Dockerfile');
|
|
12
|
+
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
let src = [];
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
// 通过 COPY 和 ADD 获取所有context中的文件
|
|
17
|
+
const ast = DockerfileParser.parse(fs.readFileSync(dockerfilePath, 'utf8'));
|
|
18
|
+
for (let a of ast.getInstructions()) {
|
|
19
|
+
if (['COPY', 'ADD'].includes(a.getInstruction())) {
|
|
20
|
+
const from = a.getArguments()[0].getValue().replace(/^\//, '');
|
|
21
|
+
const fromFullPath = path.resolve(contextDir, from);
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
23
|
+
if (fs.existsSync(fromFullPath)) {
|
|
24
|
+
const stat = fs.statSync(fromFullPath);
|
|
25
|
+
if (stat.isDirectory()) {
|
|
26
|
+
let files = await glob(path.join(from, '**'), {
|
|
27
|
+
cwd: contextDir,
|
|
28
|
+
});
|
|
29
|
+
src = src.concat(files);
|
|
30
|
+
} else if (stat.isFile()) {
|
|
31
|
+
src.push(from);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
// try use glob
|
|
35
|
+
let files = await glob(from, {
|
|
36
|
+
cwd: contextDir,
|
|
37
|
+
});
|
|
38
|
+
src = src.concat(files);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// filter by dockerignore
|
|
43
|
+
const dockerIgnoreFile = path.join(contextDir, '.dockerignore');
|
|
44
|
+
if (fs.existsSync(dockerIgnoreFile)) {
|
|
45
|
+
let ig = ignore();
|
|
46
|
+
let data = fs.readFileSync(dockerIgnoreFile, 'utf8');
|
|
47
|
+
ig.add(data.split('\n'));
|
|
48
|
+
src = ig.filter(src);
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
const dockerfile = path.relative(contextDir, dockerfilePath);
|
|
52
|
+
src.push(dockerfile); // DON'T IGNORE DOCKERFILE
|
|
53
|
+
const output = path.join(contextDir, 'lzc-build-image-context.tar');
|
|
54
|
+
return await tarContentDir(src, output, contextDir);
|
|
54
55
|
}
|
package/lib/app/lpk_installer.js
CHANGED
|
@@ -1,141 +1,138 @@
|
|
|
1
|
-
import logger from
|
|
2
|
-
import fs from
|
|
3
|
-
import path from
|
|
4
|
-
import { loadFromYaml, Downloader, unzipSync } from
|
|
5
|
-
import { DebugBridge } from
|
|
6
|
-
import shellapi from
|
|
7
|
-
import {
|
|
1
|
+
import logger from 'loglevel';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { loadFromYaml, Downloader, unzipSync } from '../utils.js';
|
|
5
|
+
import { DebugBridge } from '../debug_bridge.js';
|
|
6
|
+
import shellapi from '../shellapi.js';
|
|
7
|
+
import { t } from '../i18n/index.js';
|
|
8
|
+
import { triggerApk } from './apkshell.js';
|
|
8
9
|
|
|
9
|
-
export const installConfig = { apk: true }
|
|
10
|
+
export const installConfig = { apk: true };
|
|
10
11
|
// 从一个目录中找出修改时间最新的包
|
|
11
12
|
function findOnceLpkByDir(dir = process.cwd()) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
const pkg = fs
|
|
14
|
+
.readdirSync(dir)
|
|
15
|
+
.map((filename) => {
|
|
16
|
+
const stat = fs.statSync(path.resolve(dir, filename));
|
|
17
|
+
return { filename, mtime: stat.mtime };
|
|
18
|
+
})
|
|
19
|
+
.sort((a, b) => {
|
|
20
|
+
return b.mtime - a.mtime;
|
|
21
|
+
})
|
|
22
|
+
.find((entry) => {
|
|
23
|
+
return entry.filename.endsWith('.lpk');
|
|
24
|
+
});
|
|
25
|
+
return pkg?.filename ? path.resolve(dir, pkg.filename) : '';
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export class LpkInstaller {
|
|
28
|
-
|
|
29
|
+
constructor() { }
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
async init() { }
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// deploy 构建和安装
|
|
34
|
+
async deploy(builder) {
|
|
35
|
+
if (!builder) {
|
|
36
|
+
throw t('lzc_cli.lib.app.lpk_installer.deploy_not_exists_builder_fail', 'deploy 必须传递一个 builder');
|
|
37
|
+
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
let pkgPath = await builder.exec();
|
|
40
|
+
logger.info(t('lzc_cli.lib.app.lpk_installer.deploy_start_tips', '开始部署应用'));
|
|
41
|
+
// FIXME: 这里是前面exec输出的pkgPath还有异步的地方没有await到,临时setTimeout处理一下,后期让@llh看一下
|
|
42
|
+
await new Promise((resolve, reject) => {
|
|
43
|
+
setTimeout(async () => {
|
|
44
|
+
await this.installFromFile(pkgPath)
|
|
45
|
+
.then(() => resolve(true))
|
|
46
|
+
.catch(reject);
|
|
47
|
+
}, 50);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
async install(pkgPath) {
|
|
52
|
+
if (pkgPath.startsWith('http')) {
|
|
53
|
+
return this.installFromUrl(pkgPath);
|
|
54
|
+
} else if (fs.statSync(pkgPath).isDirectory()) {
|
|
55
|
+
return this.installFromDirectory(pkgPath);
|
|
56
|
+
} else {
|
|
57
|
+
return this.installFromFile(pkgPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
async installFromDirectory(dir) {
|
|
62
|
+
const lpk = findOnceLpkByDir(dir);
|
|
63
|
+
if (lpk) {
|
|
64
|
+
logger.info(t('lzc_cli.lib.app.lpk_installer.install_from_dir_scan_tips', `正在安装自动扫描出来的lpk包({{ lpk }})`, { lpk, interpolation: { escapeValue: false } }));
|
|
65
|
+
}
|
|
66
|
+
return this.installFromFile(lpk);
|
|
67
|
+
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
async installFromUrl(url) {
|
|
70
|
+
let downloader = new Downloader();
|
|
71
|
+
const tempDir = fs.mkdtempSync('.lzc-cli-install');
|
|
72
|
+
try {
|
|
73
|
+
let pkgPath = path.join(tempDir, 'a.lpk');
|
|
74
|
+
logger.debug(t('lzc_cli.lib.app.lpk_installer.install_form_url_download_lpk_tips', '开始下载lpk'));
|
|
75
|
+
await downloader.download(url, pkgPath);
|
|
76
|
+
logger.debug(t('lzc_cli.lib.app.lpk_installer.install_form_url_download_lpk_done_tips', '下载完成'), pkgPath);
|
|
77
|
+
await this.installFromFile(pkgPath);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
throw e;
|
|
80
|
+
} finally {
|
|
81
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
async installFromFile(pkgPath) {
|
|
86
|
+
if (!pkgPath) {
|
|
87
|
+
throw t('lzc_cli.lib.app.lpk_installer.install_from_file_lpk_path_fail', 'install 必须指定一个 pkg 路径');
|
|
88
|
+
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
if (!fs.existsSync(pkgPath)) {
|
|
91
|
+
throw t('lzc_cli.lib.app.lpk_installer.install_from_file_lpk_path_not_exists_fail', `{{ pkgPath }} 不存在`, { pkgPath, interpolation: { escapeValue: false } });
|
|
92
|
+
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
const tempDir = fs.mkdtempSync('.lzc-cli-install');
|
|
95
|
+
let manifest;
|
|
96
|
+
try {
|
|
97
|
+
unzipSync(pkgPath, tempDir, ['manifest.yml', 'icon.png']);
|
|
98
|
+
manifest = loadFromYaml(path.join(tempDir, 'manifest.yml'));
|
|
99
|
+
if (!manifest['application']['subdomain']) {
|
|
100
|
+
throw t('lzc_cli.lib.app.lpk_installer.install_from_file_manifest_not_exists_app_subdomain_fail', 'manifest.yml 中的 `application.subdomain` 字段不能为空');
|
|
101
|
+
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
logger.debug("lpk manifest", manifest)
|
|
116
|
-
} catch (err) {
|
|
117
|
-
logger.debug("parse manifest ", err)
|
|
118
|
-
} finally {
|
|
119
|
-
fs.rmSync(tempDir, { recursive: true })
|
|
120
|
-
}
|
|
103
|
+
logger.debug(t('lzc_cli.lib.app.lpk_installer.install_from_file_gen_apk_tips', '是否生成APK:'), installConfig.apk);
|
|
104
|
+
if (installConfig.apk) {
|
|
105
|
+
triggerApk(manifest['package'], manifest['name'], path.resolve(path.join(tempDir, 'icon.png'))).catch((err) => {
|
|
106
|
+
logger.debug(t('lzc_cli.lib.app.lpk_installer.install_from_file_gen_apk_error', '生成 APK 失败: '), err);
|
|
107
|
+
logger.debug(t('lzc_cli.lib.app.lpk_installer.install_from_file_gen_apk_error_tips', '生成 APK 失败,使用 lzc-cli project devshell --apk n 忽略该错误'));
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
logger.debug('lpk manifest', manifest);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
logger.debug('parse manifest ', err);
|
|
113
|
+
} finally {
|
|
114
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
115
|
+
}
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
117
|
+
try {
|
|
118
|
+
const bridge = new DebugBridge();
|
|
119
|
+
await bridge.init();
|
|
120
|
+
logger.info(t('lzc_cli.lib.app.lpk_installer.install_from_file_start_tips', '开始安装应用'));
|
|
121
|
+
await bridge.install(pkgPath, manifest ? manifest['package'] : '');
|
|
122
|
+
logger.info('\n');
|
|
123
|
+
logger.info(t('lzc_cli.lib.app.lpk_installer.install_from_file_success_tips', `安装成功!`));
|
|
124
|
+
if (manifest) {
|
|
125
|
+
logger.info(
|
|
126
|
+
t('lzc_cli.lib.app.lpk_installer.install_from_file_done_tips', `👉 请在浏览器中访问 https://{{ subdomain }}.{{ boxname }}.heiyu.space`, {
|
|
127
|
+
subdomain: manifest['application']['subdomain'],
|
|
128
|
+
boxname: shellapi.boxname,
|
|
129
|
+
interpolation: { escapeValue: false }
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
132
|
+
logger.info(t('lzc_cli.lib.app.lpk_installer.install_from_file_login_tips', `👉 并使用微服的用户名和密码登录`));
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
logger.error(t('lzc_cli.lib.app.lpk_installer.install_from_file_fail_tips', `安装失败: {{ error }}`, { error, interpolation: { escapeValue: false } }));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
141
138
|
}
|