@lazycatcloud/lzc-cli 1.3.17 → 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 +47 -7
- package/changelog.md +14 -0
- package/lib/app/apkshell.js +7 -44
- package/lib/app/index.js +178 -64
- package/lib/app/lpk_build.js +446 -61
- package/lib/app/lpk_build_images.js +749 -0
- package/lib/app/lpk_create.js +192 -45
- package/lib/app/lpk_create_generator.js +141 -13
- package/lib/app/lpk_devshell.js +33 -19
- package/lib/app/lpk_embed_images.js +257 -0
- package/lib/app/lpk_installer.js +17 -9
- package/lib/app/manifest_build.js +259 -0
- package/lib/app/project_cp.js +59 -0
- package/lib/app/project_deploy.js +58 -0
- package/lib/app/project_exec.js +82 -0
- package/lib/app/project_info.js +106 -0
- package/lib/app/project_log.js +62 -0
- package/lib/app/project_runtime.js +356 -0
- package/lib/app/project_start.js +95 -0
- package/lib/app/project_sync.js +499 -0
- package/lib/appstore/apkshell.js +50 -0
- package/lib/box/index.js +101 -4
- package/lib/box/ssh_remote.js +259 -0
- package/lib/build_remote.js +21 -0
- package/lib/debug_bridge.js +891 -83
- package/lib/docker/index.js +30 -10
- package/lib/i18n/locales/en/translation.json +262 -255
- package/lib/i18n/locales/zh/translation.json +262 -255
- package/lib/lpk/core.js +488 -0
- package/lib/lpk/index.js +210 -0
- 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 +254 -0
- package/lib/sig/index.js +88 -0
- package/lib/utils.js +94 -15
- package/package.json +3 -3
- package/scripts/cli.js +6 -0
- package/scripts/smoke/frontend-dev-entry.mjs +104 -0
- package/scripts/smoke/template-project.mjs +311 -0
- package/template/_lpk/README.md +15 -4
- package/template/_lpk/gui-vnc.manifest.yml.in +18 -0
- package/template/_lpk/hello-vue.manifest.yml.in +38 -0
- package/template/_lpk/manifest.yml.in +4 -11
- package/template/_lpk/package.yml.in +7 -0
- package/template/_lpk/todolist-golang.manifest.yml.in +30 -0
- package/template/_lpk/todolist-java.manifest.yml.in +29 -0
- package/template/_lpk/todolist-python.manifest.yml.in +37 -0
- package/template/_lpk/todolist-serverless.manifest.yml.in +38 -0
- package/template/_lpk/vue.lzc-build.yml.in +0 -44
- package/template/blank/lzc-build.dev.yml +4 -0
- package/template/blank/lzc-build.yml +24 -41
- package/template/blank/lzc-manifest.yml +7 -9
- package/template/blank/package.yml +7 -0
- package/template/golang/Dockerfile +19 -0
- package/template/golang/Dockerfile.dev +20 -0
- package/template/golang/README.md +44 -0
- package/template/golang/_gitignore +3 -0
- package/template/golang/_lzcdevignore +21 -0
- package/template/golang/go.mod +3 -0
- package/template/golang/lzc-build.dev.yml +12 -0
- package/template/golang/lzc-build.yml +16 -0
- package/template/golang/lzc-icon.png +0 -0
- package/template/golang/main.go +252 -0
- package/template/golang/manifest.dev.page.js +24 -0
- package/template/golang/run.sh +10 -0
- package/template/golang/web/index.html +238 -0
- package/template/gui-vnc/README.md +23 -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.dev.yml +4 -0
- package/template/gui-vnc/lzc-build.yml +18 -0
- package/template/gui-vnc/lzc-icon.png +0 -0
- package/template/python/Dockerfile +15 -0
- package/template/python/Dockerfile.dev +18 -0
- package/template/python/README.md +50 -0
- package/template/python/_gitignore +3 -0
- package/template/python/_lzcdevignore +21 -0
- package/template/python/app.py +110 -0
- package/template/python/lzc-build.dev.yml +12 -0
- package/template/python/lzc-build.yml +16 -0
- package/template/python/lzc-icon.png +0 -0
- package/template/python/manifest.dev.page.js +25 -0
- package/template/python/requirements.txt +1 -0
- package/template/python/run.sh +14 -0
- package/template/python/web/index.html +238 -0
- package/template/springboot/Dockerfile +20 -0
- package/template/springboot/Dockerfile.dev +20 -0
- package/template/springboot/README.md +44 -0
- package/template/springboot/_gitignore +3 -0
- package/template/springboot/_lzcdevignore +21 -0
- package/template/springboot/lzc-build.dev.yml +12 -0
- package/template/springboot/lzc-build.yml +16 -0
- package/template/springboot/lzc-icon.png +0 -0
- package/template/springboot/manifest.dev.page.js +24 -0
- package/template/springboot/pom.xml +38 -0
- package/template/springboot/run.sh +10 -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 +18 -21
- package/template/vue/lzc-build.dev.yml +7 -0
- package/template/vue/lzc-build.yml +30 -43
- package/template/vue/manifest.dev.page.js +50 -0
- package/template/vue/src/App.vue +36 -25
- package/template/vue/src/style.css +106 -49
- package/template/vue-minidb/README.md +26 -0
- package/template/vue-minidb/_gitignore +25 -0
- package/template/vue-minidb/index.html +13 -0
- package/template/vue-minidb/lzc-build.dev.yml +7 -0
- package/template/vue-minidb/lzc-build.yml +46 -0
- package/template/vue-minidb/lzc-icon.png +0 -0
- package/template/vue-minidb/manifest.dev.page.js +50 -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,
|
|
3
|
+
import { contextDirname, ensureDir, ensureDirectoryExists, dumpToYaml, isFileExist, isValidAppId, 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';
|
|
@@ -8,38 +8,113 @@ import yaml from 'js-yaml';
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import { t } from '../i18n/index.js';
|
|
10
10
|
|
|
11
|
-
let fsPromises = fs.promises;
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
function fakeLoadManifestText(text) {
|
|
13
|
+
let obj = {
|
|
14
|
+
application: {
|
|
15
|
+
subdomain: undefined,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const normalizeValue = (value) => {
|
|
20
|
+
const commentIndex = value.indexOf(' #');
|
|
21
|
+
if (commentIndex >= 0) {
|
|
22
|
+
value = value.slice(0, commentIndex);
|
|
23
|
+
}
|
|
24
|
+
return value.trim();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
String(text ?? '').split('\n').forEach((rawLine) => {
|
|
28
|
+
const line = rawLine.trim();
|
|
29
|
+
const arr = line.split(':');
|
|
30
|
+
if (arr.length !== 2) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let [key, value] = arr;
|
|
34
|
+
value = normalizeValue(value);
|
|
35
|
+
if (!obj.package && key === 'package') {
|
|
36
|
+
obj.package = value;
|
|
37
|
+
}
|
|
38
|
+
if (!obj.application.subdomain && key === 'subdomain') {
|
|
39
|
+
obj.application.subdomain = value;
|
|
40
|
+
}
|
|
41
|
+
if (!obj.version && key === 'version') {
|
|
42
|
+
obj.version = value;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return obj;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function renderTemplateText(templateFilePath, templateVars) {
|
|
49
|
+
const templateText = fs.readFileSync(templateFilePath, 'utf-8');
|
|
50
|
+
return await envsubstr(templateText, {
|
|
51
|
+
options: {
|
|
52
|
+
envs: Object.entries(templateVars).map(([key, value]) => ({
|
|
53
|
+
name: key.replace(/-/g, '_'),
|
|
54
|
+
value,
|
|
55
|
+
})),
|
|
56
|
+
syntax: 'default',
|
|
57
|
+
protect: false,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function loadTemplateYaml(text, fallbackLoader) {
|
|
63
|
+
try {
|
|
64
|
+
return {
|
|
65
|
+
data: yaml.load(text),
|
|
66
|
+
excp: false,
|
|
67
|
+
};
|
|
68
|
+
} catch {
|
|
69
|
+
return {
|
|
70
|
+
data: fallbackLoader(text),
|
|
71
|
+
excp: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class LpkTemplateFile {
|
|
77
|
+
constructor(defaultAppID, outputFileName, fallbackLoader = (text) => yaml.load(text)) {
|
|
15
78
|
this.pwd = contextDirname(import.meta.url);
|
|
16
|
-
this.manifest = {};
|
|
17
79
|
this.defaultAppID = defaultAppID;
|
|
80
|
+
this.outputFileName = outputFileName;
|
|
81
|
+
this.fallbackLoader = fallbackLoader;
|
|
82
|
+
this.data = {};
|
|
83
|
+
this.text = '';
|
|
84
|
+
this.excpTemplate = false;
|
|
18
85
|
}
|
|
19
86
|
|
|
20
|
-
async init(
|
|
21
|
-
if (!
|
|
22
|
-
|
|
87
|
+
async init(templateFilePath, askInfo = false, templateVars = null) {
|
|
88
|
+
if (!templateFilePath) {
|
|
89
|
+
throw new Error(`template file is required for ${this.outputFileName}`);
|
|
23
90
|
}
|
|
24
91
|
|
|
92
|
+
let vars = templateVars;
|
|
25
93
|
if (askInfo) {
|
|
26
|
-
|
|
27
|
-
this.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.manifest = fakeLoadManifestYml(manifestFilePath);
|
|
33
|
-
this.excpManifest = true;
|
|
34
|
-
}
|
|
94
|
+
vars = vars || (await this.askLpkInfo());
|
|
95
|
+
this.text = await renderTemplateText(templateFilePath, vars);
|
|
96
|
+
const loaded = loadTemplateYaml(this.text, this.fallbackLoader);
|
|
97
|
+
this.data = loaded.data;
|
|
98
|
+
this.excpTemplate = loaded.excp;
|
|
99
|
+
return vars;
|
|
35
100
|
}
|
|
101
|
+
|
|
102
|
+
const templateText = fs.readFileSync(templateFilePath, 'utf-8');
|
|
103
|
+
const loaded = loadTemplateYaml(templateText, this.fallbackLoader);
|
|
104
|
+
this.data = loaded.data;
|
|
105
|
+
this.excpTemplate = loaded.excp;
|
|
106
|
+
return vars;
|
|
36
107
|
}
|
|
37
108
|
|
|
38
109
|
async create(outputDir) {
|
|
39
|
-
let outputFilePath = path.join(outputDir,
|
|
110
|
+
let outputFilePath = path.join(outputDir, this.outputFileName);
|
|
40
111
|
logger.debug(`create file ${outputFilePath}`);
|
|
41
112
|
ensureDir(outputFilePath);
|
|
42
|
-
|
|
113
|
+
if (this.text) {
|
|
114
|
+
fs.writeFileSync(outputFilePath, this.text);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
return dumpToYaml(this.data, outputFilePath);
|
|
43
118
|
}
|
|
44
119
|
|
|
45
120
|
async askLpkInfo() {
|
|
@@ -61,61 +136,133 @@ export class LpkManifest {
|
|
|
61
136
|
},
|
|
62
137
|
},
|
|
63
138
|
]);
|
|
64
|
-
|
|
139
|
+
return {
|
|
65
140
|
name: appId,
|
|
66
141
|
package: `cloud.lazycat.app.${appId}`,
|
|
67
142
|
subdomain: appId,
|
|
68
143
|
};
|
|
69
|
-
return answer;
|
|
70
144
|
}
|
|
71
145
|
}
|
|
72
146
|
|
|
147
|
+
export class LpkManifest extends LpkTemplateFile {
|
|
148
|
+
constructor(defaultAppID) {
|
|
149
|
+
super(defaultAppID, 'lzc-manifest.yml', fakeLoadManifestText);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export class LpkPackageFile extends LpkTemplateFile {
|
|
154
|
+
constructor(defaultAppID) {
|
|
155
|
+
super(defaultAppID, 'package.yml');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const PROJECT_TEMPLATE_OPTIONS = [
|
|
160
|
+
{
|
|
161
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_hello_vue',
|
|
162
|
+
defaultText: 'hello-vue (Vue基础模板)',
|
|
163
|
+
value: 'hello-vue',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_java',
|
|
167
|
+
defaultText: 'todolist-java (Java Todo示例)',
|
|
168
|
+
value: 'todolist-java',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_python',
|
|
172
|
+
defaultText: 'todolist-python (Python Todo示例)',
|
|
173
|
+
value: 'todolist-python',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_golang',
|
|
177
|
+
defaultText: 'todolist-golang (Golang Todo示例)',
|
|
178
|
+
value: 'todolist-golang',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_gui_vnc',
|
|
182
|
+
defaultText: 'gui-vnc (GUI VNC Embed示例)',
|
|
183
|
+
value: 'gui-vnc',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
i18nKey: 'lzc_cli.lib.app.lpk_create.template_option_todolist_serverless',
|
|
187
|
+
defaultText: 'todolist-serverless (Serverless Todo示例)',
|
|
188
|
+
value: 'todolist-serverless',
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
export function listProjectTemplateValues() {
|
|
193
|
+
return PROJECT_TEMPLATE_OPTIONS.map((item) => item.value);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function normalizeTemplateType(rawType) {
|
|
197
|
+
const type = String(rawType ?? '').trim();
|
|
198
|
+
if (!type) {
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
201
|
+
const allowedTypes = listProjectTemplateValues();
|
|
202
|
+
if (!allowedTypes.includes(type)) {
|
|
203
|
+
throw new Error(`Unsupported template "${type}". Available templates: ${allowedTypes.join(', ')}`);
|
|
204
|
+
}
|
|
205
|
+
return type;
|
|
206
|
+
}
|
|
207
|
+
|
|
73
208
|
export class TemplateInit {
|
|
74
209
|
constructor(cwd, name, type) {
|
|
75
210
|
this.cwd = cwd;
|
|
76
211
|
this.name = name;
|
|
77
|
-
this.type = type;
|
|
212
|
+
this.type = normalizeTemplateType(type);
|
|
78
213
|
this.lpkManifest = new LpkManifest(name);
|
|
214
|
+
this.lpkPackageFile = new LpkPackageFile(name);
|
|
79
215
|
}
|
|
80
216
|
|
|
81
217
|
async init() {
|
|
82
|
-
|
|
83
|
-
this.type = await chooseTemplate();
|
|
84
|
-
}
|
|
218
|
+
this.type = await chooseTemplate(this.type);
|
|
85
219
|
|
|
86
|
-
|
|
87
|
-
const typeTemplatePath = path.join(
|
|
88
|
-
const
|
|
89
|
-
|
|
220
|
+
const templateRoot = path.join(contextDirname(import.meta.url), '..', '..', 'template', '_lpk');
|
|
221
|
+
const typeTemplatePath = path.join(templateRoot, `${this.type}.manifest.yml.in`);
|
|
222
|
+
const manifestTemplatePath = isFileExist(typeTemplatePath) ? typeTemplatePath : path.join(templateRoot, 'manifest.yml.in');
|
|
223
|
+
const packageTemplatePath = path.join(templateRoot, 'package.yml.in');
|
|
224
|
+
const templateVars = await this.lpkManifest.init(manifestTemplatePath, true);
|
|
225
|
+
await this.lpkPackageFile.init(packageTemplatePath, true, templateVars);
|
|
90
226
|
}
|
|
91
227
|
|
|
92
228
|
async create() {
|
|
93
|
-
|
|
229
|
+
const outputDir = path.resolve(this.cwd, this.name);
|
|
230
|
+
await this.lpkManifest.create(outputDir);
|
|
231
|
+
await this.lpkPackageFile.create(outputDir);
|
|
94
232
|
}
|
|
95
233
|
}
|
|
96
234
|
|
|
97
|
-
export async function chooseTemplate() {
|
|
235
|
+
export async function chooseTemplate(preselectedType = '') {
|
|
236
|
+
const fixedType = normalizeTemplateType(preselectedType);
|
|
237
|
+
if (fixedType) {
|
|
238
|
+
return fixedType;
|
|
239
|
+
}
|
|
240
|
+
|
|
98
241
|
return (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
242
|
+
await inquirer.prompt([
|
|
243
|
+
{
|
|
244
|
+
name: 'type',
|
|
245
|
+
message: t('lzc_cli.lib.app.lpk_create.choose_template_message', '选择项目构建模板'),
|
|
246
|
+
type: 'list',
|
|
247
|
+
choices: PROJECT_TEMPLATE_OPTIONS.map((item) => ({
|
|
248
|
+
name: t(item.i18nKey, item.defaultText),
|
|
249
|
+
value: item.value,
|
|
250
|
+
})),
|
|
251
|
+
},
|
|
252
|
+
])
|
|
253
|
+
)['type'];
|
|
108
254
|
}
|
|
109
255
|
|
|
110
256
|
// 创建一个应用
|
|
111
|
-
// - 先选择模板信息(golang,
|
|
257
|
+
// - 先选择模板信息(todolist-golang, hello-vue)
|
|
112
258
|
// - 根据 lpk manifest 模板中所需要的字段填充manifest
|
|
113
259
|
// - 调用模板的hook
|
|
114
260
|
class LpkCreate {
|
|
115
|
-
constructor(name, cwd = process.cwd()) {
|
|
261
|
+
constructor(name, cwd = process.cwd(), type = '') {
|
|
116
262
|
this.name = name;
|
|
117
263
|
this.cwd = cwd ?? process.cwd();
|
|
118
264
|
this.appDir = path.resolve(this.cwd, this.name);
|
|
265
|
+
this.type = normalizeTemplateType(type);
|
|
119
266
|
}
|
|
120
267
|
|
|
121
268
|
async init() {
|
|
@@ -123,7 +270,7 @@ class LpkCreate {
|
|
|
123
270
|
}
|
|
124
271
|
|
|
125
272
|
async exec() {
|
|
126
|
-
const type = await chooseTemplate();
|
|
273
|
+
const type = await chooseTemplate(this.type);
|
|
127
274
|
const template = new TemplateInit(this.cwd, this.name, type);
|
|
128
275
|
await template.init();
|
|
129
276
|
|
|
@@ -148,7 +295,7 @@ class LpkCreate {
|
|
|
148
295
|
}
|
|
149
296
|
}
|
|
150
297
|
|
|
151
|
-
export default async (name, cwd = process.cwd()) => {
|
|
152
|
-
const lpk = await new LpkCreate(name, cwd).init();
|
|
298
|
+
export default async (name, cwd = process.cwd(), type = '') => {
|
|
299
|
+
const lpk = await new LpkCreate(name, cwd, type).init();
|
|
153
300
|
return await lpk.exec();
|
|
154
301
|
};
|
|
@@ -4,7 +4,6 @@ import fs from 'fs';
|
|
|
4
4
|
import { isBinaryFileSync } from 'isbinaryfile';
|
|
5
5
|
import { contextDirname } from '../utils.js';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
// import spawn from "cross-spawn"
|
|
8
7
|
import logger from 'loglevel';
|
|
9
8
|
import { t } from '../i18n/index.js';
|
|
10
9
|
|
|
@@ -27,7 +26,6 @@ async function loadFiles(dirPath, prefix = '') {
|
|
|
27
26
|
} else {
|
|
28
27
|
content = fs.readFileSync(sourcePath, 'utf8');
|
|
29
28
|
}
|
|
30
|
-
// change _ prefix file into dot file
|
|
31
29
|
if (p.startsWith('_')) {
|
|
32
30
|
p = p.replace('_', '.');
|
|
33
31
|
}
|
|
@@ -56,19 +54,25 @@ export async function generate(type, to, opts = {}) {
|
|
|
56
54
|
writeFileTree(to, files);
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
function
|
|
57
|
+
function appCreateSuccessTipByCommands(name, installCommand = '') {
|
|
58
|
+
const installBlock = installCommand ? `\n ${installCommand}` : '';
|
|
60
59
|
console.log(
|
|
61
60
|
chalk.green(
|
|
62
61
|
t(
|
|
63
|
-
'lzc_cli.lib.app.lpk_create_generator.
|
|
62
|
+
'lzc_cli.lib.app.lpk_create_generator.app_create_success_tip_common',
|
|
64
63
|
`
|
|
65
64
|
✨ 懒猫微服应用已创建成功 !
|
|
66
|
-
✨
|
|
67
|
-
cd {{ name }}
|
|
68
|
-
lzc-cli project
|
|
65
|
+
✨ First deploy and open the app once
|
|
66
|
+
cd {{ name }}{{ installBlock }}
|
|
67
|
+
lzc-cli project deploy
|
|
68
|
+
lzc-cli project info
|
|
69
|
+
ℹ By default, project commands use lzc-build.dev.yml when it exists.
|
|
70
|
+
Each command prints the active Build config.
|
|
71
|
+
Use --release if you want to operate on lzc-build.yml.
|
|
69
72
|
`,
|
|
70
73
|
{
|
|
71
74
|
name,
|
|
75
|
+
installBlock,
|
|
72
76
|
interpolation: { escapeValue: false }
|
|
73
77
|
},
|
|
74
78
|
).trim(),
|
|
@@ -77,22 +81,146 @@ function appCreateSuccessTip(name) {
|
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
export const TemplateConfig = {
|
|
80
|
-
|
|
84
|
+
'hello-vue': {
|
|
81
85
|
build: async (to, option) => {
|
|
82
86
|
await generate('vue', to, option);
|
|
83
87
|
},
|
|
84
88
|
after: async function (name) {
|
|
85
|
-
|
|
89
|
+
appCreateSuccessTipByCommands(name);
|
|
86
90
|
console.log(
|
|
87
91
|
chalk.green(
|
|
88
92
|
t(
|
|
89
93
|
'lzc_cli.lib.app.lpk_create_generator.template_config_vue3_green',
|
|
90
94
|
`
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
🛠 Open the app first.
|
|
96
|
+
If the frontend dev server is not running yet, the app page will show the expected port and next step.
|
|
97
|
+
Then start local frontend dev:
|
|
93
98
|
npm run dev
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
The command output prints the active Build config.
|
|
100
|
+
🔎 For troubleshooting:
|
|
101
|
+
lzc-cli project log -f
|
|
102
|
+
`,
|
|
103
|
+
).trim(),
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
'todolist-java': {
|
|
109
|
+
build: async (to, option) => {
|
|
110
|
+
await generate('springboot', to, option);
|
|
111
|
+
},
|
|
112
|
+
after: async function (name) {
|
|
113
|
+
appCreateSuccessTipByCommands(name);
|
|
114
|
+
console.log(
|
|
115
|
+
chalk.green(
|
|
116
|
+
t(
|
|
117
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_springboot_green',
|
|
118
|
+
`
|
|
119
|
+
🛠 Open the app first.
|
|
120
|
+
If the backend dev service is not ready yet, the app page will tell you how to sync or copy code and how to start the service.
|
|
121
|
+
Recommended backend dev loop:
|
|
122
|
+
lzc-cli project sync --watch
|
|
123
|
+
lzc-cli project exec /bin/sh
|
|
124
|
+
The command output prints the active Build config.
|
|
125
|
+
🔎 For troubleshooting:
|
|
126
|
+
lzc-cli project log -f
|
|
127
|
+
`,
|
|
128
|
+
).trim(),
|
|
129
|
+
),
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
'todolist-python': {
|
|
134
|
+
build: async (to, option) => {
|
|
135
|
+
await generate('python', to, option);
|
|
136
|
+
},
|
|
137
|
+
after: async function (name) {
|
|
138
|
+
appCreateSuccessTipByCommands(name);
|
|
139
|
+
console.log(
|
|
140
|
+
chalk.green(
|
|
141
|
+
t(
|
|
142
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_python_green',
|
|
143
|
+
`
|
|
144
|
+
🛠 Open the app first.
|
|
145
|
+
If the backend dev service is not ready yet, the app page will tell you how to sync or copy code and how to start the service.
|
|
146
|
+
Recommended backend dev loop:
|
|
147
|
+
lzc-cli project sync --watch
|
|
148
|
+
lzc-cli project exec /bin/sh
|
|
149
|
+
The command output prints the active Build config.
|
|
150
|
+
🔎 For troubleshooting:
|
|
151
|
+
lzc-cli project log -f
|
|
152
|
+
`,
|
|
153
|
+
).trim(),
|
|
154
|
+
),
|
|
155
|
+
);
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
'todolist-golang': {
|
|
159
|
+
build: async (to, option) => {
|
|
160
|
+
await generate('golang', to, option);
|
|
161
|
+
},
|
|
162
|
+
after: async function (name) {
|
|
163
|
+
appCreateSuccessTipByCommands(name);
|
|
164
|
+
console.log(
|
|
165
|
+
chalk.green(
|
|
166
|
+
t(
|
|
167
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_golang_green',
|
|
168
|
+
`
|
|
169
|
+
🛠 Open the app first.
|
|
170
|
+
If the backend dev service is not ready yet, the app page will tell you how to sync or copy code and how to start the service.
|
|
171
|
+
Recommended backend dev loop:
|
|
172
|
+
lzc-cli project sync --watch
|
|
173
|
+
lzc-cli project exec /bin/sh
|
|
174
|
+
The command output prints the active Build config.
|
|
175
|
+
🔎 For troubleshooting:
|
|
176
|
+
lzc-cli project log -f
|
|
177
|
+
`,
|
|
178
|
+
).trim(),
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
'gui-vnc': {
|
|
184
|
+
build: async (to, option) => {
|
|
185
|
+
await generate('gui-vnc', to, option);
|
|
186
|
+
},
|
|
187
|
+
after: async function (name) {
|
|
188
|
+
appCreateSuccessTipByCommands(name);
|
|
189
|
+
console.log(
|
|
190
|
+
chalk.green(
|
|
191
|
+
t(
|
|
192
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_gui_vnc_green',
|
|
193
|
+
`
|
|
194
|
+
🛠 GUI VNC app (embedded image template):
|
|
195
|
+
lzc-cli project deploy
|
|
196
|
+
The command output prints the active Build config.
|
|
197
|
+
🔎 For troubleshooting:
|
|
198
|
+
lzc-cli project log -f
|
|
199
|
+
lzc-cli project exec -s desktop /bin/sh
|
|
200
|
+
`,
|
|
201
|
+
).trim(),
|
|
202
|
+
),
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
'todolist-serverless': {
|
|
207
|
+
build: async (to, option) => {
|
|
208
|
+
await generate('vue-minidb', to, option);
|
|
209
|
+
},
|
|
210
|
+
after: async function (name) {
|
|
211
|
+
appCreateSuccessTipByCommands(name);
|
|
212
|
+
console.log(
|
|
213
|
+
chalk.green(
|
|
214
|
+
t(
|
|
215
|
+
'lzc_cli.lib.app.lpk_create_generator.template_config_vue_minidb_green',
|
|
216
|
+
`
|
|
217
|
+
🛠 Open the app first.
|
|
218
|
+
If the frontend dev server is not running yet, the app page will show the expected port and next step.
|
|
219
|
+
Then start local frontend dev:
|
|
220
|
+
npm run dev
|
|
221
|
+
The command output prints the active Build config.
|
|
222
|
+
🔎 For troubleshooting:
|
|
223
|
+
lzc-cli project log -f
|
|
96
224
|
`,
|
|
97
225
|
).trim(),
|
|
98
226
|
),
|
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'],
|
|
@@ -263,7 +265,7 @@ export class AppDevShell {
|
|
|
263
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'];
|
|
@@ -291,7 +293,7 @@ export class AppDevShell {
|
|
|
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
|
}
|