@lazycatcloud/lzc-cli 2.0.0-pre.2 → 2.0.0-pre.4
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 +16 -0
- package/lib/app/lpk_build.js +55 -27
- package/lib/app/lpk_create.js +8 -7
- package/lib/app/lpk_create_generator.js +26 -10
- package/package.json +1 -1
- package/template/_lpk/README.md +1 -0
- package/template/blank/lzc-build.dev.yml +5 -2
- package/template/golang/lzc-build.dev.yml +5 -2
- package/template/gui-vnc/lzc-build.dev.yml +5 -2
- package/template/python/lzc-build.dev.yml +5 -2
- package/template/springboot/lzc-build.dev.yml +5 -2
- package/template/vue/lzc-build.dev.yml +5 -2
- package/template/vue-minidb/lzc-build.dev.yml +5 -2
package/changelog.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.0.0-pre.4](https://gitee.com/linakesi/lzc-cli/compare/v2.0.0-pre.3...v2.0.0-pre.4) (2026-03-14)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- support build package metadata overrides
|
|
8
|
+
|
|
9
|
+
## [2.0.0-pre.3](https://gitee.com/linakesi/lzc-cli/compare/v2.0.0-pre.2...v2.0.0-pre.3) (2026-03-12)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- refresh the backend template assets and set `mini_os_version` to `v1.5.0`
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- use top-level override semantics for dev build config
|
|
18
|
+
|
|
3
19
|
## [2.0.0-pre.2](https://gitee.com/linakesi/lzc-cli/compare/v2.0.0-pre.1...v2.0.0-pre.2) (2026-03-12)
|
|
4
20
|
|
|
5
21
|
### Bug Fixes
|
package/lib/app/lpk_build.js
CHANGED
|
@@ -11,7 +11,6 @@ import yaml from 'js-yaml';
|
|
|
11
11
|
import { buildConfiguredImagesToTempDir } from './lpk_build_images.js';
|
|
12
12
|
import { pipeline } from 'node:stream/promises';
|
|
13
13
|
import { t } from '../i18n/index.js';
|
|
14
|
-
import mergeWith from 'lodash.mergewith';
|
|
15
14
|
|
|
16
15
|
async function archiveFolderTo(appDir, out, format = 'zip') {
|
|
17
16
|
return new Promise(async (resolve, reject) => {
|
|
@@ -298,24 +297,45 @@ function formatBytes(bytes) {
|
|
|
298
297
|
}
|
|
299
298
|
|
|
300
299
|
function mergeBuildOptions(baseOptions, topOptions) {
|
|
301
|
-
return
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return undefined;
|
|
306
|
-
});
|
|
300
|
+
return {
|
|
301
|
+
...(baseOptions ?? {}),
|
|
302
|
+
...(topOptions ?? {}),
|
|
303
|
+
};
|
|
307
304
|
}
|
|
308
305
|
|
|
309
|
-
function
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (!normalizedSuffix) {
|
|
313
|
-
return normalizedPackageId;
|
|
306
|
+
function normalizePackageMetadataOverride(options, fieldName) {
|
|
307
|
+
if (!Object.prototype.hasOwnProperty.call(options ?? {}, fieldName)) {
|
|
308
|
+
return '';
|
|
314
309
|
}
|
|
315
|
-
|
|
316
|
-
|
|
310
|
+
const normalizedValue = String(options[fieldName] ?? '').trim();
|
|
311
|
+
if (!normalizedValue) {
|
|
312
|
+
throw new Error(`${fieldName} cannot be empty when specified`);
|
|
317
313
|
}
|
|
318
|
-
return
|
|
314
|
+
return normalizedValue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function applyPackageMetadataOverrides(manifest, packageInfo, options) {
|
|
318
|
+
const pkgId = normalizePackageMetadataOverride(options, 'pkg_id');
|
|
319
|
+
const pkgName = normalizePackageMetadataOverride(options, 'pkg_name');
|
|
320
|
+
const hasPackageMetadataOverrides = !!pkgId || !!pkgName;
|
|
321
|
+
let nextManifest = { ...(manifest ?? {}) };
|
|
322
|
+
let nextPackageInfo = packageInfo;
|
|
323
|
+
|
|
324
|
+
if (pkgId) {
|
|
325
|
+
nextManifest = { ...nextManifest, package: pkgId };
|
|
326
|
+
nextPackageInfo = { ...(nextPackageInfo ?? {}), package: pkgId };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (pkgName) {
|
|
330
|
+
nextManifest = { ...nextManifest, name: pkgName };
|
|
331
|
+
nextPackageInfo = { ...(nextPackageInfo ?? {}), name: pkgName };
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
manifest: nextManifest,
|
|
336
|
+
packageInfo: nextPackageInfo,
|
|
337
|
+
hasPackageMetadataOverrides,
|
|
338
|
+
};
|
|
319
339
|
}
|
|
320
340
|
|
|
321
341
|
export function validatePackageFileForArchiveFormat(hasPackageFile, archiveFormat) {
|
|
@@ -331,8 +351,8 @@ function hasBuildEnvEntries(envEntries) {
|
|
|
331
351
|
return Array.isArray(envEntries) && envEntries.length > 0;
|
|
332
352
|
}
|
|
333
353
|
|
|
334
|
-
export function shouldUseV2PackageLayout({ forceV2 = false, hasPackageFile = false, hasImagesConfig = false, buildEnvEntries = [] } = {}) {
|
|
335
|
-
return !!forceV2 || !!hasPackageFile || !!hasImagesConfig || hasBuildEnvEntries(buildEnvEntries);
|
|
354
|
+
export function shouldUseV2PackageLayout({ forceV2 = false, hasPackageFile = false, hasImagesConfig = false, buildEnvEntries = [], hasPackageMetadataOverrides = false } = {}) {
|
|
355
|
+
return !!forceV2 || !!hasPackageFile || !!hasImagesConfig || hasBuildEnvEntries(buildEnvEntries) || !!hasPackageMetadataOverrides;
|
|
336
356
|
}
|
|
337
357
|
|
|
338
358
|
function logDeprecatedStaticFieldWarning(manifestPath, fields) {
|
|
@@ -350,6 +370,16 @@ function normalizeBuildOptions(options) {
|
|
|
350
370
|
return normalized;
|
|
351
371
|
}
|
|
352
372
|
|
|
373
|
+
function normalizeContentDir(contentdir) {
|
|
374
|
+
if (contentdir === undefined || contentdir === null) {
|
|
375
|
+
return '';
|
|
376
|
+
}
|
|
377
|
+
if (typeof contentdir === 'string') {
|
|
378
|
+
return contentdir.trim();
|
|
379
|
+
}
|
|
380
|
+
return contentdir;
|
|
381
|
+
}
|
|
382
|
+
|
|
353
383
|
function loadYamlIfExists(filePath) {
|
|
354
384
|
if (!filePath || !isFileExist(filePath)) {
|
|
355
385
|
return {};
|
|
@@ -399,6 +429,7 @@ export class LpkBuild {
|
|
|
399
429
|
this.sourceManifest = null;
|
|
400
430
|
this.packageInfo = null;
|
|
401
431
|
this.hasPackageFile = false;
|
|
432
|
+
this.hasPackageMetadataOverrides = false;
|
|
402
433
|
this.buildVars = null;
|
|
403
434
|
this.preprocessedManifestText = '';
|
|
404
435
|
|
|
@@ -427,6 +458,7 @@ export class LpkBuild {
|
|
|
427
458
|
this.sourceManifest = null;
|
|
428
459
|
this.packageInfo = null;
|
|
429
460
|
this.hasPackageFile = false;
|
|
461
|
+
this.hasPackageMetadataOverrides = false;
|
|
430
462
|
this.buildVars = buildVarsFromEnvEntries(this.options['envs']);
|
|
431
463
|
this.preprocessedManifestText = '';
|
|
432
464
|
return this;
|
|
@@ -479,15 +511,10 @@ export class LpkBuild {
|
|
|
479
511
|
this.sourceManifest = loaded.sourceManifest;
|
|
480
512
|
this.packageInfo = loaded.packageInfo;
|
|
481
513
|
this.hasPackageFile = loaded.hasPackageFile;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
this.manifest = { ...this.manifest, package: packageWithSuffix };
|
|
487
|
-
if (this.hasPackageFile) {
|
|
488
|
-
this.packageInfo = { ...(this.packageInfo ?? {}), package: packageWithSuffix };
|
|
489
|
-
}
|
|
490
|
-
}
|
|
514
|
+
const packageMetadata = applyPackageMetadataOverrides(loaded.manifest, loaded.packageInfo, this.options);
|
|
515
|
+
this.manifest = packageMetadata.manifest;
|
|
516
|
+
this.packageInfo = packageMetadata.packageInfo;
|
|
517
|
+
this.hasPackageMetadataOverrides = packageMetadata.hasPackageMetadataOverrides;
|
|
491
518
|
|
|
492
519
|
if (!isValidPackageName(this.manifest['package'])) {
|
|
493
520
|
throw t('lzc_cli.lib.app.lpk_build.get_manifest_package_name_fail', `{{ package }} 含有非法字符,请使用正确的包名格式(java的包名格式),如:cloud.lazycat.apps.video`, {
|
|
@@ -541,7 +568,7 @@ export class LpkBuild {
|
|
|
541
568
|
}
|
|
542
569
|
|
|
543
570
|
const tempDir = fs.mkdtempSync('.lzc-cli-build');
|
|
544
|
-
let contentdir = this.options['contentdir'];
|
|
571
|
+
let contentdir = normalizeContentDir(this.options['contentdir']);
|
|
545
572
|
let browserExtension = this.options['browser-extension'];
|
|
546
573
|
let aiPodService = this.options['ai-pod-service'];
|
|
547
574
|
try {
|
|
@@ -652,6 +679,7 @@ export class LpkBuild {
|
|
|
652
679
|
hasPackageFile: this.hasPackageFile,
|
|
653
680
|
hasImagesConfig,
|
|
654
681
|
buildEnvEntries: this.options['envs'],
|
|
682
|
+
hasPackageMetadataOverrides: this.hasPackageMetadataOverrides,
|
|
655
683
|
});
|
|
656
684
|
if (useV2PackageLayout) {
|
|
657
685
|
logDeprecatedStaticFieldWarning(this.manifestFilePath, findManifestStaticFields(this.sourceManifest));
|
package/lib/app/lpk_create.js
CHANGED
|
@@ -212,17 +212,18 @@ export class TemplateInit {
|
|
|
212
212
|
this.type = normalizeTemplateType(type);
|
|
213
213
|
this.lpkManifest = new LpkManifest(name);
|
|
214
214
|
this.lpkPackageFile = new LpkPackageFile(name);
|
|
215
|
+
this.templateVars = null;
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
async init() {
|
|
218
219
|
this.type = await chooseTemplate(this.type);
|
|
219
220
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
221
|
+
const templateRoot = path.join(contextDirname(import.meta.url), '..', '..', 'template', '_lpk');
|
|
222
|
+
const typeTemplatePath = path.join(templateRoot, `${this.type}.manifest.yml.in`);
|
|
223
|
+
const manifestTemplatePath = isFileExist(typeTemplatePath) ? typeTemplatePath : path.join(templateRoot, 'manifest.yml.in');
|
|
224
|
+
const packageTemplatePath = path.join(templateRoot, 'package.yml.in');
|
|
225
|
+
this.templateVars = await this.lpkManifest.init(manifestTemplatePath, true);
|
|
226
|
+
await this.lpkPackageFile.init(packageTemplatePath, true, this.templateVars);
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
async create() {
|
|
@@ -286,7 +287,7 @@ class LpkCreate {
|
|
|
286
287
|
),
|
|
287
288
|
);
|
|
288
289
|
}
|
|
289
|
-
|
|
290
|
+
await TemplateConfig[type].build(path.resolve(this.cwd, this.name), { templateVars: template.templateVars });
|
|
290
291
|
|
|
291
292
|
console.log(chalk.green(t('lzc_cli.lib.app.lpk_create.exec_init_project_success_tips', `✨ 初始化懒猫云应用`)));
|
|
292
293
|
await TemplateConfig[type].after(this.name, this.cwd);
|
|
@@ -8,8 +8,23 @@ import logger from 'loglevel';
|
|
|
8
8
|
import { t } from '../i18n/index.js';
|
|
9
9
|
|
|
10
10
|
const __dirname = contextDirname(import.meta.url);
|
|
11
|
+
const PROJECT_CREATE_PACKAGE_DEV_PLACEHOLDER = '__PROJECT_CREATE_PACKAGE_DEV__';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
function renderProjectCreateFileContent(filePath, content, opts = {}) {
|
|
14
|
+
if (typeof content !== 'string' || path.basename(filePath) !== 'lzc-build.dev.yml') {
|
|
15
|
+
return content;
|
|
16
|
+
}
|
|
17
|
+
if (!content.includes(PROJECT_CREATE_PACKAGE_DEV_PLACEHOLDER)) {
|
|
18
|
+
return content;
|
|
19
|
+
}
|
|
20
|
+
const packageId = String(opts.templateVars?.package ?? '').trim();
|
|
21
|
+
if (!packageId) {
|
|
22
|
+
throw new Error(`templateVars.package is required for ${filePath}`);
|
|
23
|
+
}
|
|
24
|
+
return content.replaceAll(PROJECT_CREATE_PACKAGE_DEV_PLACEHOLDER, `${packageId}.dev`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function loadFiles(dirPath, prefix = '', opts = {}) {
|
|
13
28
|
const templateRoot = path.join(__dirname, '..', '..', 'template');
|
|
14
29
|
const templateDir = path.join(templateRoot, dirPath);
|
|
15
30
|
|
|
@@ -26,15 +41,16 @@ async function loadFiles(dirPath, prefix = '') {
|
|
|
26
41
|
} else {
|
|
27
42
|
content = fs.readFileSync(sourcePath, 'utf8');
|
|
28
43
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
if (p.startsWith('_')) {
|
|
45
|
+
p = p.replace('_', '.');
|
|
46
|
+
}
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
const outputPath = path.join(prefix, p);
|
|
49
|
+
files[outputPath] = {
|
|
50
|
+
content: renderProjectCreateFileContent(outputPath, content, opts),
|
|
51
|
+
mode,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
38
54
|
return files;
|
|
39
55
|
}
|
|
40
56
|
|
|
@@ -50,7 +66,7 @@ function writeFileTree(target, files) {
|
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
export async function generate(type, to, opts = {}) {
|
|
53
|
-
const files = await loadFiles(type, opts.prefix);
|
|
69
|
+
const files = await loadFiles(type, opts.prefix, opts);
|
|
54
70
|
writeFileTree(to, files);
|
|
55
71
|
}
|
|
56
72
|
|
package/package.json
CHANGED
package/template/_lpk/README.md
CHANGED
|
@@ -9,6 +9,7 @@ lzc-cli project info
|
|
|
9
9
|
默认情况下,project 命令在存在 `lzc-build.dev.yml` 时会优先使用它。
|
|
10
10
|
每个命令都会打印实际使用的 `Build config`。
|
|
11
11
|
如果要操作 `lzc-build.yml`,请显式加上 `--release`。
|
|
12
|
+
`lzc-build.dev.yml` 中出现的同名顶层字段会整体覆盖 `lzc-build.yml`,不会做递归 merge。
|
|
12
13
|
如果是前端模板,`project deploy` 会按 `buildscript` 自动安装依赖并完成构建,不需要额外先执行 `npm install`。
|
|
13
14
|
|
|
14
15
|
## 构建
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# 开发态覆盖配置
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# 覆盖开发态包名,避免覆盖 release 安装包
|
|
4
|
+
pkg_id: __PROJECT_CREATE_PACKAGE_DEV__
|
|
5
|
+
|
|
6
|
+
# 覆盖 release 配置中的 contentdir;留空表示开发态不打包内容目录
|
|
7
|
+
contentdir:
|
|
5
8
|
|
|
6
9
|
envs:
|
|
7
10
|
- DEV_MODE=1
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# 开发态覆盖配置
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# 覆盖开发态包名,避免覆盖 release 安装包
|
|
4
|
+
pkg_id: __PROJECT_CREATE_PACKAGE_DEV__
|
|
5
|
+
|
|
6
|
+
# 覆盖 release 配置中的 contentdir;留空表示开发态不打包内容目录
|
|
7
|
+
contentdir:
|
|
5
8
|
|
|
6
9
|
envs:
|
|
7
10
|
- DEV_MODE=1
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# 开发态覆盖配置
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# 覆盖开发态包名,避免覆盖 release 安装包
|
|
4
|
+
pkg_id: __PROJECT_CREATE_PACKAGE_DEV__
|
|
5
|
+
|
|
6
|
+
# 覆盖 release 配置中的 contentdir;留空表示开发态不打包内容目录
|
|
7
|
+
contentdir:
|
|
5
8
|
|
|
6
9
|
envs:
|
|
7
10
|
- DEV_MODE=1
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# 开发态覆盖配置
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# 覆盖开发态包名,避免覆盖 release 安装包
|
|
4
|
+
pkg_id: __PROJECT_CREATE_PACKAGE_DEV__
|
|
5
|
+
|
|
6
|
+
# 覆盖 release 配置中的 contentdir;留空表示开发态不打包内容目录
|
|
7
|
+
contentdir:
|
|
5
8
|
|
|
6
9
|
envs:
|
|
7
10
|
- DEV_MODE=1
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# 开发态覆盖配置
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
3
|
+
# 覆盖开发态包名,避免覆盖 release 安装包
|
|
4
|
+
pkg_id: __PROJECT_CREATE_PACKAGE_DEV__
|
|
5
|
+
|
|
6
|
+
# 覆盖 release 配置中的 contentdir;留空表示开发态不打包内容目录
|
|
7
|
+
contentdir:
|
|
5
8
|
|
|
6
9
|
envs:
|
|
7
10
|
- DEV_MODE=1
|