@lazycatcloud/lzc-cli 1.3.13 → 2.0.0-pre.0
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 +30 -5
- package/changelog.md +16 -0
- package/lib/app/index.js +174 -58
- package/lib/app/lpk_build.js +197 -18
- package/lib/app/lpk_build_images.js +728 -0
- package/lib/app/lpk_create.js +96 -23
- package/lib/app/lpk_create_generator.js +150 -12
- package/lib/app/lpk_devshell.js +35 -21
- package/lib/app/lpk_embed_images.js +257 -0
- package/lib/app/lpk_installer.js +15 -7
- package/lib/app/project_cp.js +64 -0
- package/lib/app/project_deploy.js +33 -0
- package/lib/app/project_exec.js +45 -0
- package/lib/app/project_info.js +106 -0
- package/lib/app/project_log.js +67 -0
- package/lib/app/project_runtime.js +261 -0
- package/lib/app/project_start.js +100 -0
- package/lib/appstore/index.js +56 -16
- package/lib/appstore/publish.js +16 -13
- package/lib/box/index.js +103 -6
- package/lib/box/ssh_remote.js +259 -0
- package/lib/build_remote.js +22 -0
- package/lib/config/index.js +4 -3
- package/lib/debug_bridge.js +837 -44
- package/lib/docker/index.js +30 -10
- package/lib/i18n/index.js +1 -0
- package/lib/i18n/locales/en/translation.json +263 -250
- package/lib/i18n/locales/zh/translation.json +57 -44
- package/lib/lpk/core.js +487 -0
- package/lib/lpk/index.js +210 -0
- package/lib/shellapi.js +5 -5
- package/lib/sig/core.js +254 -0
- package/lib/sig/index.js +88 -0
- package/lib/utils.js +17 -12
- package/package.json +4 -3
- package/scripts/cli.js +4 -0
- package/template/_lpk/README.md +11 -3
- package/template/_lpk/gui-vnc.manifest.yml.in +27 -0
- package/template/_lpk/manifest.yml.in +4 -2
- package/template/_lpk/todolist-golang.manifest.yml.in +16 -0
- package/template/_lpk/todolist-java.manifest.yml.in +15 -0
- package/template/_lpk/todolist-python.manifest.yml.in +15 -0
- package/template/_lpk/vue.lzc-build.yml.in +0 -44
- package/template/blank/_gitignore +1 -0
- package/template/blank/lzc-build.yml +25 -40
- package/template/blank/lzc-manifest.yml +14 -7
- package/template/golang/Dockerfile +19 -0
- package/template/golang/README.md +33 -0
- package/template/golang/_gitignore +3 -0
- package/template/golang/go.mod +3 -0
- package/template/golang/lzc-build.yml +21 -0
- package/template/golang/lzc-icon.png +0 -0
- package/template/golang/main.go +252 -0
- package/template/golang/run.sh +3 -0
- package/template/golang/web/index.html +238 -0
- package/template/gui-vnc/README.md +19 -0
- package/template/gui-vnc/_gitignore +2 -0
- package/template/gui-vnc/images/Dockerfile +30 -0
- package/template/gui-vnc/images/kasmvnc.yaml +33 -0
- package/template/gui-vnc/images/startup-script.desktop +9 -0
- package/template/gui-vnc/images/startup-script.sh +6 -0
- package/template/gui-vnc/lzc-build.yml +23 -0
- package/template/gui-vnc/lzc-icon.png +0 -0
- package/template/python/Dockerfile +15 -0
- package/template/python/README.md +33 -0
- package/template/python/_gitignore +3 -0
- package/template/python/app.py +110 -0
- package/template/python/lzc-build.yml +21 -0
- package/template/python/lzc-icon.png +0 -0
- package/template/python/requirements.txt +1 -0
- package/template/python/run.sh +3 -0
- package/template/python/web/index.html +238 -0
- package/template/springboot/Dockerfile +20 -0
- package/template/springboot/README.md +33 -0
- package/template/springboot/_gitignore +3 -0
- package/template/springboot/lzc-build.yml +21 -0
- package/template/springboot/lzc-icon.png +0 -0
- package/template/springboot/pom.xml +38 -0
- package/template/springboot/run.sh +3 -0
- package/template/springboot/src/main/java/cloud/lazycat/app/Application.java +132 -0
- package/template/springboot/src/main/resources/application.properties +1 -0
- package/template/springboot/src/main/resources/static/index.html +238 -0
- package/template/vue/README.md +17 -7
- package/template/vue/_gitignore +1 -0
- package/template/vue/lzc-build.yml +31 -42
- package/template/vue/src/App.vue +36 -25
- package/template/vue/src/style.css +106 -49
- package/template/vue-minidb/README.md +34 -0
- package/template/vue-minidb/_gitignore +26 -0
- package/template/vue-minidb/index.html +13 -0
- package/template/vue-minidb/lzc-build.yml +48 -0
- package/template/vue-minidb/lzc-icon.png +0 -0
- package/template/vue-minidb/package.json +21 -0
- package/template/vue-minidb/public/vite.svg +1 -0
- package/template/vue-minidb/src/App.vue +206 -0
- package/template/vue-minidb/src/assets/vue.svg +1 -0
- package/template/vue-minidb/src/main.ts +5 -0
- package/template/vue-minidb/src/style.css +136 -0
- package/template/vue-minidb/src/vite-env.d.ts +1 -0
- package/template/vue-minidb/tsconfig.app.json +24 -0
- package/template/vue-minidb/tsconfig.json +7 -0
- package/template/vue-minidb/tsconfig.node.json +22 -0
- package/template/vue-minidb/vite.config.ts +10 -0
- /package/template/{vue → vue-minidb}/src/components/HelloWorld.vue +0 -0
package/lib/app/lpk_create.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logger from 'loglevel';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import { contextDirname, loadFromYaml,
|
|
3
|
+
import { contextDirname, loadFromYaml, ensureDir, ensureDirectoryExists, dumpToYaml, isFileExist, isValidAppId, fakeLoadManifestYml, envsubstr } from '../utils.js';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { TemplateConfig } from './lpk_create_generator.js';
|
|
6
6
|
import fs from 'node:fs';
|
|
@@ -10,10 +10,60 @@ import { t } from '../i18n/index.js';
|
|
|
10
10
|
|
|
11
11
|
let fsPromises = fs.promises;
|
|
12
12
|
|
|
13
|
+
const PROJECT_TEMPLATE_OPTIONS = [
|
|
14
|
+
{
|
|
15
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_hello_vue',
|
|
16
|
+
defaultText: 'hello-vue (Vue基础模板)',
|
|
17
|
+
value: 'hello-vue',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_java',
|
|
21
|
+
defaultText: 'todolist-java (Java Todo示例)',
|
|
22
|
+
value: 'todolist-java',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_python',
|
|
26
|
+
defaultText: 'todolist-python (Python Todo示例)',
|
|
27
|
+
value: 'todolist-python',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_golang',
|
|
31
|
+
defaultText: 'todolist-golang (Golang Todo示例)',
|
|
32
|
+
value: 'todolist-golang',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_gui_vnc',
|
|
36
|
+
defaultText: 'gui-vnc (GUI VNC Embed示例)',
|
|
37
|
+
value: 'gui-vnc',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_serverless',
|
|
41
|
+
defaultText: 'todolist-serverless (Serverless Todo示例)',
|
|
42
|
+
value: 'todolist-serverless',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
export function listProjectTemplateValues() {
|
|
47
|
+
return PROJECT_TEMPLATE_OPTIONS.map((item) => item.value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function normalizeTemplateType(rawType) {
|
|
51
|
+
const type = String(rawType ?? '').trim();
|
|
52
|
+
if (!type) {
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
const allowedTypes = listProjectTemplateValues();
|
|
56
|
+
if (!allowedTypes.includes(type)) {
|
|
57
|
+
throw new Error(`Unsupported template "${type}". Available templates: ${allowedTypes.join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
return type;
|
|
60
|
+
}
|
|
61
|
+
|
|
13
62
|
export class LpkManifest {
|
|
14
63
|
constructor(defaultAppID) {
|
|
15
64
|
this.pwd = contextDirname(import.meta.url);
|
|
16
65
|
this.manifest = {};
|
|
66
|
+
this.manifestText = '';
|
|
17
67
|
this.defaultAppID = defaultAppID;
|
|
18
68
|
}
|
|
19
69
|
|
|
@@ -24,7 +74,18 @@ export class LpkManifest {
|
|
|
24
74
|
|
|
25
75
|
if (askInfo) {
|
|
26
76
|
let answer = await this.askLpkInfo();
|
|
27
|
-
|
|
77
|
+
const manifestTemplate = fs.readFileSync(manifestFilePath, 'utf-8');
|
|
78
|
+
this.manifestText = await envsubstr(manifestTemplate, {
|
|
79
|
+
options: {
|
|
80
|
+
envs: Object.entries(answer).map(([key, value]) => ({
|
|
81
|
+
name: key.replace(/-/g, '_'),
|
|
82
|
+
value,
|
|
83
|
+
})),
|
|
84
|
+
syntax: 'default',
|
|
85
|
+
protect: false,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
this.manifest = yaml.load(this.manifestText);
|
|
28
89
|
} else {
|
|
29
90
|
try {
|
|
30
91
|
this.manifest = loadFromYaml(manifestFilePath);
|
|
@@ -39,6 +100,10 @@ export class LpkManifest {
|
|
|
39
100
|
let outputFilePath = path.join(outputDir, 'lzc-manifest.yml');
|
|
40
101
|
logger.debug(`create file ${outputFilePath}`);
|
|
41
102
|
ensureDir(outputFilePath);
|
|
103
|
+
if (this.manifestText) {
|
|
104
|
+
fs.writeFileSync(outputFilePath, this.manifestText);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
42
107
|
return dumpToYaml(this.manifest, outputFilePath);
|
|
43
108
|
}
|
|
44
109
|
|
|
@@ -74,14 +139,12 @@ export class TemplateInit {
|
|
|
74
139
|
constructor(cwd, name, type) {
|
|
75
140
|
this.cwd = cwd;
|
|
76
141
|
this.name = name;
|
|
77
|
-
this.type = type;
|
|
142
|
+
this.type = normalizeTemplateType(type);
|
|
78
143
|
this.lpkManifest = new LpkManifest(name);
|
|
79
144
|
}
|
|
80
145
|
|
|
81
146
|
async init() {
|
|
82
|
-
|
|
83
|
-
this.type = await chooseTemplate();
|
|
84
|
-
}
|
|
147
|
+
this.type = await chooseTemplate(this.type);
|
|
85
148
|
|
|
86
149
|
// 优先使用模板项目自定义的模板文件
|
|
87
150
|
const typeTemplatePath = path.join(contextDirname(import.meta.url), '..', '..', 'template', '_lpk', `${this.type}.manifest.yml.in`);
|
|
@@ -94,28 +157,37 @@ export class TemplateInit {
|
|
|
94
157
|
}
|
|
95
158
|
}
|
|
96
159
|
|
|
97
|
-
export async function chooseTemplate() {
|
|
160
|
+
export async function chooseTemplate(preselectedType = '') {
|
|
161
|
+
const fixedType = normalizeTemplateType(preselectedType);
|
|
162
|
+
if (fixedType) {
|
|
163
|
+
return fixedType;
|
|
164
|
+
}
|
|
165
|
+
|
|
98
166
|
return (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
167
|
+
await inquirer.prompt([
|
|
168
|
+
{
|
|
169
|
+
name: 'type',
|
|
170
|
+
message: t('lzc_cli.lib.app.lpk_create.choose_template_message', '选择项目构建模板'),
|
|
171
|
+
type: 'list',
|
|
172
|
+
choices: PROJECT_TEMPLATE_OPTIONS.map((item) => ({
|
|
173
|
+
name: t(item.i18nKey, item.defaultText),
|
|
174
|
+
value: item.value,
|
|
175
|
+
})),
|
|
176
|
+
},
|
|
177
|
+
])
|
|
178
|
+
)['type'];
|
|
108
179
|
}
|
|
109
180
|
|
|
110
181
|
// 创建一个应用
|
|
111
|
-
// - 先选择模板信息(golang,
|
|
182
|
+
// - 先选择模板信息(todolist-golang, hello-vue)
|
|
112
183
|
// - 根据 lpk manifest 模板中所需要的字段填充manifest
|
|
113
184
|
// - 调用模板的hook
|
|
114
185
|
class LpkCreate {
|
|
115
|
-
constructor(name, cwd = process.cwd()) {
|
|
186
|
+
constructor(name, cwd = process.cwd(), type = '') {
|
|
116
187
|
this.name = name;
|
|
117
188
|
this.cwd = cwd ?? process.cwd();
|
|
118
189
|
this.appDir = path.resolve(this.cwd, this.name);
|
|
190
|
+
this.type = normalizeTemplateType(type);
|
|
119
191
|
}
|
|
120
192
|
|
|
121
193
|
async init() {
|
|
@@ -123,17 +195,18 @@ class LpkCreate {
|
|
|
123
195
|
}
|
|
124
196
|
|
|
125
197
|
async exec() {
|
|
126
|
-
const type = await chooseTemplate();
|
|
198
|
+
const type = await chooseTemplate(this.type);
|
|
127
199
|
const template = new TemplateInit(this.cwd, this.name, type);
|
|
128
200
|
await template.init();
|
|
129
201
|
|
|
130
|
-
console.log(chalk.green(t('lzc_cli.lib.app.lpk_create.exec_init_project_tips', `✨ 初始化项目 {{name}}`, { name: this.name })));
|
|
202
|
+
console.log(chalk.green(t('lzc_cli.lib.app.lpk_create.exec_init_project_tips', `✨ 初始化项目 {{ name }}`, { name: this.name, interpolation: { escapeValue: false } })));
|
|
131
203
|
const { isExists, renamedFileName } = ensureDirectoryExists(this.appDir, true);
|
|
132
204
|
if (isExists && renamedFileName) {
|
|
133
205
|
console.warn(
|
|
134
206
|
chalk.yellow(
|
|
135
|
-
t('lzc_cli.lib.app.lpk_create.exec_init_project_name_exist_tips', `! 检测到相同目录,已自动将旧目录重命名为 {{renamedFileName}}`, {
|
|
207
|
+
t('lzc_cli.lib.app.lpk_create.exec_init_project_name_exist_tips', `! 检测到相同目录,已自动将旧目录重命名为 {{ renamedFileName }}`, {
|
|
136
208
|
renamedFileName,
|
|
209
|
+
interpolation: { escapeValue: false }
|
|
137
210
|
}),
|
|
138
211
|
),
|
|
139
212
|
);
|
|
@@ -147,7 +220,7 @@ class LpkCreate {
|
|
|
147
220
|
}
|
|
148
221
|
}
|
|
149
222
|
|
|
150
|
-
export default async (name, cwd = process.cwd()) => {
|
|
151
|
-
const lpk = await new LpkCreate(name, cwd).init();
|
|
223
|
+
export default async (name, cwd = process.cwd(), type = '') => {
|
|
224
|
+
const lpk = await new LpkCreate(name, cwd, type).init();
|
|
152
225
|
return await lpk.exec();
|
|
153
226
|
};
|
|
@@ -46,7 +46,7 @@ function writeFileTree(target, files) {
|
|
|
46
46
|
if (!fs.existsSync(path.dirname(filePath))) {
|
|
47
47
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
48
48
|
}
|
|
49
|
-
logger.debug(t('lzc_cli.lib.app.lpk_create_generator.write_file_tree_create_file', `创建文件 {{filePath}}`, { filePath }));
|
|
49
|
+
logger.debug(t('lzc_cli.lib.app.lpk_create_generator.write_file_tree_create_file', `创建文件 {{ filePath }}`, { filePath, interpolation: { escapeValue: false } }));
|
|
50
50
|
fs.writeFileSync(filePath, files[p].content, { mode: files[p].mode });
|
|
51
51
|
});
|
|
52
52
|
}
|
|
@@ -63,33 +63,171 @@ function appCreateSuccessTip(name) {
|
|
|
63
63
|
'lzc_cli.lib.app.lpk_create_generator.app_create_success_tip',
|
|
64
64
|
`
|
|
65
65
|
✨ 懒猫微服应用已创建成功 !
|
|
66
|
-
✨
|
|
67
|
-
cd {{name}}
|
|
68
|
-
|
|
66
|
+
✨ 先完成第一次部署,确认手机/PC都可以访问
|
|
67
|
+
cd {{ name }}
|
|
68
|
+
npm install
|
|
69
|
+
lzc-cli project deploy
|
|
70
|
+
lzc-cli project info
|
|
71
|
+
`,
|
|
72
|
+
{
|
|
73
|
+
name,
|
|
74
|
+
interpolation: { escapeValue: false }
|
|
75
|
+
},
|
|
76
|
+
).trim(),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function appCreateSuccessTipByCommands(name, installCommand = '') {
|
|
82
|
+
const installBlock = installCommand ? `\n ${installCommand}` : '';
|
|
83
|
+
console.log(
|
|
84
|
+
chalk.green(
|
|
85
|
+
t(
|
|
86
|
+
'lzc_cli.lib.app.lpk_create_generator.app_create_success_tip_common',
|
|
87
|
+
`
|
|
88
|
+
✨ 懒猫微服应用已创建成功 !
|
|
89
|
+
✨ 先完成第一次部署,确认手机/PC都可以访问
|
|
90
|
+
cd {{ name }}{{ installBlock }}
|
|
91
|
+
lzc-cli project deploy
|
|
92
|
+
lzc-cli project info
|
|
69
93
|
`,
|
|
70
|
-
{
|
|
94
|
+
{
|
|
95
|
+
name,
|
|
96
|
+
installBlock,
|
|
97
|
+
interpolation: { escapeValue: false }
|
|
98
|
+
},
|
|
71
99
|
).trim(),
|
|
72
100
|
),
|
|
73
101
|
);
|
|
74
102
|
}
|
|
75
103
|
|
|
76
104
|
export const TemplateConfig = {
|
|
77
|
-
|
|
105
|
+
'hello-vue': {
|
|
78
106
|
build: async (to, option) => {
|
|
79
107
|
await generate('vue', to, option);
|
|
80
108
|
},
|
|
81
109
|
after: async function (name) {
|
|
82
|
-
|
|
110
|
+
appCreateSuccessTipByCommands(name);
|
|
83
111
|
console.log(
|
|
84
112
|
chalk.green(
|
|
85
113
|
t(
|
|
86
114
|
'lzc_cli.lib.app.lpk_create_generator.template_config_vue3_green',
|
|
87
115
|
`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
116
|
+
🛠 修改源码后,重新执行部署即可查看效果:
|
|
117
|
+
lzc-cli project deploy
|
|
118
|
+
🔎 如果要排查问题:
|
|
119
|
+
lzc-cli project log -f
|
|
120
|
+
lzc-cli project exec /bin/sh
|
|
121
|
+
`,
|
|
122
|
+
).trim(),
|
|
123
|
+
),
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'todolist-java': {
|
|
128
|
+
build: async (to, option) => {
|
|
129
|
+
await generate('springboot', to, option);
|
|
130
|
+
},
|
|
131
|
+
after: async function (name) {
|
|
132
|
+
appCreateSuccessTipByCommands(name);
|
|
133
|
+
console.log(
|
|
134
|
+
chalk.green(
|
|
135
|
+
t(
|
|
136
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_springboot_green',
|
|
137
|
+
`
|
|
138
|
+
🛠 Spring Boot app starts inside image build/runtime:
|
|
139
|
+
lzc-cli project deploy
|
|
140
|
+
🔎 For troubleshooting:
|
|
141
|
+
lzc-cli project log -f
|
|
142
|
+
lzc-cli project exec /bin/sh
|
|
143
|
+
`,
|
|
144
|
+
).trim(),
|
|
145
|
+
),
|
|
146
|
+
);
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
'todolist-python': {
|
|
150
|
+
build: async (to, option) => {
|
|
151
|
+
await generate('python', to, option);
|
|
152
|
+
},
|
|
153
|
+
after: async function (name) {
|
|
154
|
+
appCreateSuccessTipByCommands(name);
|
|
155
|
+
console.log(
|
|
156
|
+
chalk.green(
|
|
157
|
+
t(
|
|
158
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_python_green',
|
|
159
|
+
`
|
|
160
|
+
🛠 Flask app starts in container runtime:
|
|
161
|
+
lzc-cli project deploy
|
|
162
|
+
🔎 For troubleshooting:
|
|
163
|
+
lzc-cli project log -f
|
|
164
|
+
lzc-cli project exec /bin/sh
|
|
165
|
+
`,
|
|
166
|
+
).trim(),
|
|
167
|
+
),
|
|
168
|
+
);
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
'todolist-golang': {
|
|
172
|
+
build: async (to, option) => {
|
|
173
|
+
await generate('golang', to, option);
|
|
174
|
+
},
|
|
175
|
+
after: async function (name) {
|
|
176
|
+
appCreateSuccessTipByCommands(name);
|
|
177
|
+
console.log(
|
|
178
|
+
chalk.green(
|
|
179
|
+
t(
|
|
180
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_golang_green',
|
|
181
|
+
`
|
|
182
|
+
🛠 Golang app starts in container runtime:
|
|
183
|
+
lzc-cli project deploy
|
|
184
|
+
🔎 For troubleshooting:
|
|
185
|
+
lzc-cli project log -f
|
|
186
|
+
lzc-cli project exec /bin/sh
|
|
187
|
+
`,
|
|
188
|
+
).trim(),
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
'gui-vnc': {
|
|
194
|
+
build: async (to, option) => {
|
|
195
|
+
await generate('gui-vnc', to, option);
|
|
196
|
+
},
|
|
197
|
+
after: async function (name) {
|
|
198
|
+
appCreateSuccessTipByCommands(name);
|
|
199
|
+
console.log(
|
|
200
|
+
chalk.green(
|
|
201
|
+
t(
|
|
202
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_gui_vnc_green',
|
|
203
|
+
`
|
|
204
|
+
🛠 GUI VNC app (embedded image template):
|
|
205
|
+
lzc-cli project deploy
|
|
206
|
+
🔎 For troubleshooting:
|
|
207
|
+
lzc-cli project log -f
|
|
208
|
+
lzc-cli project exec -s desktop /bin/sh
|
|
209
|
+
`,
|
|
210
|
+
).trim(),
|
|
211
|
+
),
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
'todolist-serverless': {
|
|
216
|
+
build: async (to, option) => {
|
|
217
|
+
await generate('vue-minidb', to, option);
|
|
218
|
+
},
|
|
219
|
+
after: async function (name) {
|
|
220
|
+
appCreateSuccessTipByCommands(name);
|
|
221
|
+
console.log(
|
|
222
|
+
chalk.green(
|
|
223
|
+
t(
|
|
224
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_vue_minidb_green',
|
|
225
|
+
`
|
|
226
|
+
🛠 This template includes @lazycatcloud/minidb:
|
|
227
|
+
lzc-cli project deploy
|
|
228
|
+
🔎 For troubleshooting:
|
|
229
|
+
lzc-cli project log -f
|
|
230
|
+
lzc-cli project exec /bin/sh
|
|
93
231
|
`,
|
|
94
232
|
).trim(),
|
|
95
233
|
),
|
package/lib/app/lpk_devshell.js
CHANGED
|
@@ -30,6 +30,7 @@ import { DebugBridge } from '../debug_bridge.js';
|
|
|
30
30
|
import shellApi from '../shellapi.js';
|
|
31
31
|
import { t } from '../i18n/index.js';
|
|
32
32
|
import { collectContextFromDockerFile } from './lpk_devshell_docker.js';
|
|
33
|
+
import { resolveBuildRemoteFromOptions } from '../build_remote.js';
|
|
33
34
|
|
|
34
35
|
// 判断是否需要重新构建
|
|
35
36
|
// - 先判断 lzc-build.yml 是否发生改变
|
|
@@ -44,6 +45,7 @@ class AppDevShellMonitor {
|
|
|
44
45
|
|
|
45
46
|
this.optionsFilePath = path.join(this.pwd, buildConfigFile);
|
|
46
47
|
this.options = loadFromYaml(this.optionsFilePath);
|
|
48
|
+
this.buildRemote = resolveBuildRemoteFromOptions(this.options, `file:${this.optionsFilePath}`);
|
|
47
49
|
|
|
48
50
|
this.manifestFilePath = this.options['manifest'] ? path.join(this.pwd, this.options['manifest']) : path.join(this.pwd, 'lzc-manifest.yml');
|
|
49
51
|
|
|
@@ -54,7 +56,7 @@ class AppDevShellMonitor {
|
|
|
54
56
|
this.cacheFilePath = undefined;
|
|
55
57
|
this.oldHash = undefined;
|
|
56
58
|
this.newHash = undefined;
|
|
57
|
-
this.bridge = new DebugBridge();
|
|
59
|
+
this.bridge = new DebugBridge(this.pwd, this.buildRemote);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
async init() {
|
|
@@ -101,6 +103,7 @@ export class AppDevShell {
|
|
|
101
103
|
this.buildConfigFile = buildConfigFile;
|
|
102
104
|
this.isUserApp = false;
|
|
103
105
|
this.monitor = undefined;
|
|
106
|
+
this.buildRemote = resolveBuildRemoteFromOptions(this.lpkBuild.options, `file:${this.lpkBuild.optionsFilePath}`);
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
async init() {
|
|
@@ -225,7 +228,6 @@ export class AppDevShell {
|
|
|
225
228
|
// 避免应用永远处于 unhealth 导致状态卡在 starting
|
|
226
229
|
this.lpkBuild.onBeforeDumpYaml(async (manifest, options) => {
|
|
227
230
|
logger.debug('merge lzc-build.yml devshell services\n', options);
|
|
228
|
-
const userapp = this.isUserApp ? shellApi.uid + '.' : '';
|
|
229
231
|
const devshell = {
|
|
230
232
|
application: {
|
|
231
233
|
devshell: options['devshell'],
|
|
@@ -260,10 +262,10 @@ export class AppDevShell {
|
|
|
260
262
|
await createTemplateFileCommon(dockerfilePath, path.join(tempDir, 'Dockerfile'), { dependencies: depsStr });
|
|
261
263
|
|
|
262
264
|
const label = `${await md5String(depsStr)}:latest`;
|
|
263
|
-
logger.debug(t('lzc_cli.lib.app.lpk_devshell.devshell_build_image_for_box_tips', `开始在盒子中构建 {{label}} 镜像 from {{tempDir}}`, { label, tempDir }));
|
|
265
|
+
logger.debug(t('lzc_cli.lib.app.lpk_devshell.devshell_build_image_for_box_tips', `开始在盒子中构建 {{ label }} 镜像 from {{ tempDir }}`, { label, tempDir, interpolation: { escapeValue: false } }));
|
|
264
266
|
|
|
265
267
|
const contextTar = await collectContextFromDockerFile(tempDir, path.resolve(tempDir, 'Dockerfile'));
|
|
266
|
-
const bridge = new DebugBridge();
|
|
268
|
+
const bridge = new DebugBridge(this.cwd, this.buildRemote);
|
|
267
269
|
await bridge.init();
|
|
268
270
|
const tag = await bridge.buildImage(label, contextTar);
|
|
269
271
|
delete manifest['application']['devshell'];
|
|
@@ -287,11 +289,11 @@ export class AppDevShell {
|
|
|
287
289
|
}
|
|
288
290
|
|
|
289
291
|
const label = `${manifest['package']}-devshell:${manifest['version']}`;
|
|
290
|
-
logger.debug(t('lzc_cli.lib.app.lpk_devshell.devshell_build_label_image_box_tips', `开始在盒子中构建 {{label}} 镜像`, { label }));
|
|
292
|
+
logger.debug(t('lzc_cli.lib.app.lpk_devshell.devshell_build_label_image_box_tips', `开始在盒子中构建 {{ label }} 镜像`, { label, interpolation: { escapeValue: false } }));
|
|
291
293
|
|
|
292
294
|
const contextTar = await collectContextFromDockerFile(process.cwd(), path.resolve(process.cwd(), config['build'], 'Dockerfile'));
|
|
293
295
|
|
|
294
|
-
const bridge = new DebugBridge();
|
|
296
|
+
const bridge = new DebugBridge(this.cwd, this.buildRemote);
|
|
295
297
|
await bridge.init();
|
|
296
298
|
const tag = await bridge.buildImage(label, contextTar);
|
|
297
299
|
delete manifest['application']['devshell'];
|
|
@@ -323,15 +325,9 @@ export class AppDevShell {
|
|
|
323
325
|
return manifest;
|
|
324
326
|
});
|
|
325
327
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return manifest;
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
// 添加一个 devshell 的标记在 lpk 中,标记当前 lpk 为一个 debug 版本
|
|
333
|
-
this.lpkBuild.onBeforeDumpLpk(async (options, cwd, destDir) => {
|
|
334
|
-
fs.writeFileSync(path.resolve(destDir, 'devshell'), '');
|
|
328
|
+
// 添加一个 devshell 的标记在 lpk 中,标记当前 lpk 为一个 debug 版本
|
|
329
|
+
this.lpkBuild.onBeforeDumpLpk(async (options, cwd, destDir) => {
|
|
330
|
+
fs.writeFileSync(path.resolve(destDir, 'devshell'), '');
|
|
335
331
|
});
|
|
336
332
|
|
|
337
333
|
// 在构建生成 lpk 包后,调用 deploy 进行部署
|
|
@@ -343,7 +339,7 @@ export class AppDevShell {
|
|
|
343
339
|
async rsyncShell() {
|
|
344
340
|
const manifest = await this.lpkBuild.getManifest();
|
|
345
341
|
const pkgId = manifest['package'];
|
|
346
|
-
const devshell = new DevShell(pkgId, this.isUserApp);
|
|
342
|
+
const devshell = new DevShell(pkgId, this.isUserApp, this.cwd, this.buildRemote);
|
|
347
343
|
try {
|
|
348
344
|
await devshell.shell();
|
|
349
345
|
} catch (e) {
|
|
@@ -357,16 +353,34 @@ export class AppDevShell {
|
|
|
357
353
|
}
|
|
358
354
|
|
|
359
355
|
class DevShell {
|
|
360
|
-
constructor(appId, isUserApp) {
|
|
356
|
+
constructor(appId, isUserApp, cwd = process.cwd(), buildRemote = null) {
|
|
361
357
|
this.appId = appId;
|
|
362
358
|
this.isUserApp = isUserApp;
|
|
359
|
+
this.cwd = cwd;
|
|
360
|
+
this.buildRemote = buildRemote;
|
|
361
|
+
this.syncUID = '';
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async resolveUID() {
|
|
365
|
+
if (!this.buildRemote) {
|
|
366
|
+
return shellApi.uid;
|
|
367
|
+
}
|
|
368
|
+
if (this.syncUID) {
|
|
369
|
+
return this.syncUID;
|
|
370
|
+
}
|
|
371
|
+
const bridge = new DebugBridge(this.cwd, this.buildRemote);
|
|
372
|
+
await bridge.init();
|
|
373
|
+
this.syncUID = await bridge.resolveCurrentUID();
|
|
374
|
+
return this.syncUID;
|
|
363
375
|
}
|
|
364
376
|
|
|
365
377
|
async syncProject(appId) {
|
|
366
|
-
const
|
|
378
|
+
const uid = await this.resolveUID();
|
|
379
|
+
const resolvedIp = this.buildRemote ? this.buildRemote.sshHost : await resolveDomain(`dev.${shellApi.boxname}.heiyu.space`);
|
|
367
380
|
const rsyncDebug = isDebugMode() ? '-P' : '';
|
|
368
|
-
const destDir = `${appId}${this.isUserApp ? '/' +
|
|
369
|
-
const
|
|
381
|
+
const destDir = `${appId}${this.isUserApp ? '/' + uid : ''}`;
|
|
382
|
+
const rsyncHost = resolvedIp.includes(':') ? `[${resolvedIp}]` : resolvedIp;
|
|
383
|
+
const dest = `rsync://${uid}@${rsyncHost}:874/lzcapp_cache/${destDir}/devshell`;
|
|
370
384
|
const rsyncCmd = isWindows ? path.join(contextDirname(import.meta.url), '..', '..', 'template', '_lpk', 'win-rsync', 'rsync.exe') : `rsync`;
|
|
371
385
|
|
|
372
386
|
try {
|
|
@@ -454,7 +468,7 @@ class DevShell {
|
|
|
454
468
|
}
|
|
455
469
|
|
|
456
470
|
async connectShell(onconnect = null) {
|
|
457
|
-
const bridge = new DebugBridge();
|
|
471
|
+
const bridge = new DebugBridge(this.cwd, this.buildRemote);
|
|
458
472
|
await bridge.init();
|
|
459
473
|
await bridge.devshell(this.appId, this.isUserApp, onconnect);
|
|
460
474
|
}
|