@lazycatcloud/lzc-cli 1.3.12 → 1.3.13

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.
@@ -1,376 +1,359 @@
1
- import path from "node:path"
2
- import fs from "node:fs"
3
- import logger from "loglevel"
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ import logger from 'loglevel';
4
4
  import {
5
- loadFromYaml,
6
- isDirExist,
7
- isDirSync,
8
- isFileExist,
9
- dumpToYaml,
10
- envTemplateFile,
11
- isValidPackageName,
12
- tarContentDir,
13
- isPngWithFile,
14
- isMacOs,
15
- isWindows,
16
- isLinux
17
- } from "../utils.js"
18
- import spawn from "cross-spawn"
19
- import { LpkManifest } from "./lpk_create.js"
20
- import archiver from "archiver"
21
- import yaml from "js-yaml"
22
-
23
- async function archiveFolderTo(appDir, out, format = "zip") {
24
- return new Promise(async (resolve, reject) => {
25
- if (!fs.existsSync(appDir)) {
26
- reject(new Error(`${appDir} 文件夹不存在`))
27
- return
28
- }
29
-
30
- logger.debug("start archive app ...")
31
- const output = fs.createWriteStream(out)
32
- const archive = archiver(format)
33
-
34
- archive.on("error", (e) => {
35
- reject(e)
36
- logger.error(e)
37
- })
38
- archive.on("end", () => {
39
- resolve(output)
40
- })
41
- archive.pipe(output)
42
-
43
- archive.directory(appDir, false)
44
- archive.finalize()
45
- })
5
+ loadFromYaml,
6
+ isDirExist,
7
+ isDirSync,
8
+ isFileExist,
9
+ dumpToYaml,
10
+ envTemplateFile,
11
+ isValidPackageName,
12
+ tarContentDir,
13
+ isPngWithFile,
14
+ isMacOs,
15
+ isWindows,
16
+ isLinux,
17
+ } from '../utils.js';
18
+ import spawn from 'cross-spawn';
19
+ import { LpkManifest } from './lpk_create.js';
20
+ import archiver from 'archiver';
21
+ import yaml from 'js-yaml';
22
+ import { t } from '../i18n/index.js';
23
+
24
+ async function archiveFolderTo(appDir, out, format = 'zip') {
25
+ return new Promise(async (resolve, reject) => {
26
+ if (!fs.existsSync(appDir)) {
27
+ reject(new Error(t('lzc_cli.lib.app.lpk_build.archive_folder_to_exist_fail', `{{appDir}} 文件夹不存在`, { appDir })));
28
+ return;
29
+ }
30
+
31
+ logger.debug('start archive app ...');
32
+ const output = fs.createWriteStream(out);
33
+ const archive = archiver(format);
34
+
35
+ archive.on('error', (e) => {
36
+ reject(e);
37
+ logger.error(e);
38
+ });
39
+ archive.on('end', () => {
40
+ resolve(output);
41
+ });
42
+ archive.pipe(output);
43
+
44
+ archive.directory(appDir, false);
45
+ archive.finalize();
46
+ });
46
47
  }
47
48
 
48
49
  async function fetchIconTo(options, cwd, destDir) {
49
- if (!options["icon"]) {
50
- logger.warn("图标icon 没有指定")
51
- return
52
- }
53
-
54
- let iconPath = options["icon"]
55
- if (path.extname(iconPath) !== ".png") {
56
- logger.warn("图标icon 不是一个 .png 文件")
57
- return
58
- }
59
-
60
- if (!path.isAbsolute(iconPath)) {
61
- iconPath = path.resolve(cwd, iconPath)
62
- }
63
-
64
- if (!isFileExist(iconPath)) {
65
- logger.warn(`图标icon ${iconPath} 不存在`)
66
- return
67
- }
68
-
69
- if (!isPngWithFile(iconPath)) {
70
- logger.warn(`图标icon ${iconPath} 验证失败(不是一个png格式)`)
71
- return
72
- } else {
73
- logger.debug(`图标icon ${iconPath} 验证成功(png格式)`)
74
- }
75
-
76
- fs.copyFileSync(iconPath, path.join(destDir, "icon.png"))
77
- return
50
+ if (!options['icon']) {
51
+ logger.warn(t('lzc_cli.lib.app.lpk_build.fetch_icon_to_icon_empty_fail', '图标icon 没有指定'));
52
+ return;
53
+ }
54
+
55
+ let iconPath = options['icon'];
56
+ if (path.extname(iconPath) !== '.png') {
57
+ logger.warn(t('lzc_cli.lib.app.lpk_build.fetch_icon_to_icon_extname_fail', '图标icon 不是一个 .png 文件'));
58
+ return;
59
+ }
60
+
61
+ if (!path.isAbsolute(iconPath)) {
62
+ iconPath = path.resolve(cwd, iconPath);
63
+ }
64
+
65
+ if (!isFileExist(iconPath)) {
66
+ logger.warn(t('lzc_cli.lib.app.lpk_build.fetch_icon_to_icon_file_not_exist_fail', `图标icon {{iconPath}} 不存在`, { iconPath }));
67
+ return;
68
+ }
69
+
70
+ if (!isPngWithFile(iconPath)) {
71
+ logger.warn(t('lzc_cli.lib.app.lpk_build.fetch_icon_to_icon_not_is_png_fail', `图标icon {{iconPath}} 验证失败(不是一个png格式)`, { iconPath }));
72
+ return;
73
+ } else {
74
+ logger.debug(t('lzc_cli.lib.app.lpk_build.fetch_icon_to_icon_is_png', `图标icon {{iconPath}} 验证成功(png格式)`, { iconPath }));
75
+ }
76
+
77
+ fs.copyFileSync(iconPath, path.join(destDir, 'icon.png'));
78
+ return;
78
79
  }
79
80
 
80
81
  async function fetchLzcDeployParamTo(options, cwd, destDir) {
81
- let deployParamsPath = options["deploy_params"]
82
- if (!deployParamsPath) {
83
- logger.debug("deploy_params 没有指定")
84
- let cwdDeployParamsPath = path.join(cwd, "lzc-deploy-params.yml")
85
- if (isFileExist(cwdDeployParamsPath)) {
86
- deployParamsPath = cwdDeployParamsPath
87
- logger.debug("检测当前目录下具有 lzc-deploy-params.yml")
88
- }
89
- }
90
- if (!deployParamsPath) {
91
- return
92
- }
93
-
94
- if (!path.isAbsolute(deployParamsPath)) {
95
- deployParamsPath = path.resolve(cwd, deployParamsPath)
96
- }
97
-
98
- if (!isFileExist(deployParamsPath)) {
99
- logger.warn(`deploy_params ${deployParamsPath} 不存在`)
100
- return
101
- }
102
-
103
- fs.copyFileSync(deployParamsPath, path.join(destDir, "deploy_params.yml"))
104
- return
82
+ let deployParamsPath = options['deploy_params'];
83
+ if (!deployParamsPath) {
84
+ logger.debug('deploy_params not specified');
85
+ let cwdDeployParamsPath = path.join(cwd, 'lzc-deploy-params.yml');
86
+ if (isFileExist(cwdDeployParamsPath)) {
87
+ deployParamsPath = cwdDeployParamsPath;
88
+ logger.debug(t('lzc_cli.lib.app.lpk_build.fetch_lzc_deploy_param_to_exist', '检测当前目录下具有 lzc-deploy-params.yml'));
89
+ }
90
+ }
91
+ if (!deployParamsPath) {
92
+ return;
93
+ }
94
+
95
+ if (!path.isAbsolute(deployParamsPath)) {
96
+ deployParamsPath = path.resolve(cwd, deployParamsPath);
97
+ }
98
+
99
+ if (!isFileExist(deployParamsPath)) {
100
+ logger.warn(t('lzc_cli.lib.app.lpk_build.fetch_lzc_deploy_param_to_not_exist', `deploy_params {{deployParamsPath}} 不存在`, { deployParamsPath }));
101
+ return;
102
+ }
103
+
104
+ fs.copyFileSync(deployParamsPath, path.join(destDir, 'deploy_params.yml'));
105
+ return;
105
106
  }
106
107
 
107
108
  // 提供一些方便的环境变量,可以在 lzc-build.yml 中直接使用
108
109
  // - LocalIP 本地局域网ip
109
110
  function localIp() {
110
- const regex = /inet6 (fc03:1136:[0-9a-fA-F:]+)[?:\/ ]/
111
-
112
- let output = ""
113
- if (isMacOs) {
114
- const result = spawn.sync("sh", ["-c", "ifconfig"], {
115
- encoding: "utf-8"
116
- })
117
- if (result.status != 0 || result.error) {
118
- logger.debug("macos get current ip is error", result.error)
119
- return ""
120
- }
121
- output = result.stdout
122
- } else if (isWindows) {
123
- logger.debug(`当前 Windows 不支持使用 LocalIP 反代`)
124
- return ""
125
- } else {
126
- const result = spawn.sync("ip", ["addr", "show", "heiyu-0"], {
127
- encoding: "utf-8"
128
- })
129
- if (result.status !== 0 || result.error) {
130
- logger.debug("run ip addr show heiyu-0 failed", result.error)
131
- return ""
132
- }
133
- output = result.stdout
134
- }
135
- const match = output.match(regex)
136
- if (match) {
137
- return `[${match[1]}]`
138
- } else {
139
- logger.debug("get LocalIP environment error", output.stderr)
140
- return ""
141
- }
111
+ const regex = /inet6 (fc03:1136:[0-9a-fA-F:]+)[?:\/ ]/;
112
+
113
+ let output = '';
114
+ if (isMacOs) {
115
+ const result = spawn.sync('sh', ['-c', 'ifconfig'], {
116
+ encoding: 'utf-8',
117
+ });
118
+ if (result.status != 0 || result.error) {
119
+ logger.debug('macos get current ip is error', result.error);
120
+ return '';
121
+ }
122
+ output = result.stdout;
123
+ } else if (isWindows) {
124
+ logger.debug(t('lzc_cli.lib.app.lpk_build.local_ip_is_windows_fail', `当前 Windows 不支持使用 LocalIP 反代`));
125
+ return '';
126
+ } else {
127
+ const result = spawn.sync('ip', ['addr', 'show', 'heiyu-0'], {
128
+ encoding: 'utf-8',
129
+ });
130
+ if (result.status !== 0 || result.error) {
131
+ logger.debug('run ip addr show heiyu-0 failed', result.error);
132
+ return '';
133
+ }
134
+ output = result.stdout;
135
+ }
136
+ const match = output.match(regex);
137
+ if (match) {
138
+ return `[${match[1]}]`;
139
+ } else {
140
+ logger.debug('get LocalIP environment error', output.stderr);
141
+ return '';
142
+ }
142
143
  }
143
144
  function convenientEnv() {
144
- return Object.assign(
145
- {},
146
- {
147
- LocalIP: localIp()
148
- },
149
- process.env
150
- )
145
+ return Object.assign(
146
+ {},
147
+ {
148
+ LocalIP: localIp(),
149
+ },
150
+ process.env,
151
+ );
151
152
  }
152
153
 
153
154
  export class LpkBuild {
154
- constructor(cwd, buildConfigFile) {
155
- this.pwd = cwd ?? process.cwd()
156
-
157
- this.optionsFilePath = path.join(this.pwd, buildConfigFile)
158
- this.options = loadFromYaml(this.optionsFilePath)
159
-
160
- this.manifestFilePath = this.options["manifest"]
161
- ? path.join(this.pwd, this.options["manifest"])
162
- : path.join(this.pwd, "lzc-manifest.yml")
163
- this.manifest = null
164
-
165
- this.beforeBuildPackageFn = []
166
- this.beforeDumpYamlFn = []
167
- this.beforeTarContentFn = []
168
- this.beforeDumpLpkFn = [fetchIconTo, fetchLzcDeployParamTo]
169
- }
170
-
171
- // init 时替换 lzc-build.yml 中的模板字段
172
- async init() {
173
- const manifest = await this.getManifest()
174
- const primitive = convenientEnv()
175
- this.options = yaml.load(
176
- await envTemplateFile(
177
- this.optionsFilePath,
178
- Object.assign({}, primitive, manifest)
179
- )
180
- )
181
- return this
182
- }
183
-
184
- // onBeforeDumpYaml
185
- // fn: function(manifest, options) => manifest
186
- onBeforeDumpYaml(fn) {
187
- this.beforeDumpYamlFn.push(fn)
188
- }
189
- // onBeforeTarContent
190
- // fn: function(contentdir, options) => void
191
- onBeforeTarContent(fn) {
192
- this.beforeTarContentFn.push(fn)
193
- }
194
- // onBeforeBuildPackage
195
- // fn: function(options) => options
196
- onBeforeBuildPackage(fn) {
197
- this.beforeBuildPackageFn.push(fn)
198
- }
199
-
200
- // onBeforeDumpLpk
201
- // fn: function(options, cwd, dir) => void
202
- onBeforeDumpLpk(fn) {
203
- this.beforeDumpLpkFn.push(fn)
204
- }
205
-
206
- async getManifest() {
207
- if (this.manifest) {
208
- return this.manifest
209
- }
210
-
211
- let lpkM = new LpkManifest()
212
- await lpkM.init(this.manifestFilePath)
213
- this.manifest = lpkM.manifest
214
- // manifest使用 text/template模板时,标记为异常manifest
215
- // 创建lpk时,直接将源文件拷入 lpk
216
- this.excpManifest = lpkM.excpManifest
217
-
218
- if (!isValidPackageName(this.manifest["package"])) {
219
- throw `${this.manifest["package"]} 含有非法字符,请使用正确的包名格式(java的包名格式),如:cloud.lazycat.apps.video`
220
- }
221
-
222
- if (!this.manifest["application"]["subdomain"]) {
223
- throw `application 模块下的 subdomain 字段不能为空`
224
- }
225
-
226
- return this.manifest
227
- }
228
-
229
- async exec() {
230
- if (this.beforeBuildPackageFn.length > 0) {
231
- this.options = await this.beforeBuildPackageFn.reduce(
232
- async (prev, curr) => {
233
- return await curr(await prev)
234
- },
235
- this.options
236
- )
237
- }
238
-
239
- if (this.options["buildscript"]) {
240
- const cmd = isWindows ? "cmd" : "sh"
241
- const cmdArgs = isWindows ? "/c" : "-c"
242
- let p = spawn.sync(cmd, [cmdArgs, this.options["buildscript"]], {
243
- cwd: this.pwd,
244
- stdio: "inherit"
245
- })
246
- if (p.status != 0) {
247
- throw `构建失败`
248
- }
249
- } else {
250
- logger.warn("跳过执行 buildscript")
251
- }
252
-
253
- // 输出路径
254
- let packName = this.options["lpkPath"]
255
- const pkgout = path.resolve(this.pwd, this.options["pkgout"])
256
- if (!packName && !isDirExist(pkgout)) {
257
- throw `${pkgout} 不存在`
258
- }
259
-
260
- const tempDir = fs.mkdtempSync(".lzc-cli-build")
261
- let contentdir = this.options["contentdir"]
262
- let browserExtension = this.options["browser-extension"]
263
- let aiPodService = this.options["ai-pod-service"]
264
- try {
265
- if (contentdir) {
266
- contentdir = path.resolve(this.pwd, contentdir)
267
- if (!isDirExist(contentdir)) {
268
- throw `${contentdir} 不存在`
269
- }
270
- } else {
271
- logger.warn("跳过拷贝 contentdir 内容")
272
- // 当没有指定的 contentdir 的时候,也生成一个空的文件夹
273
- // 原因是:可能其他地方会复制内容进来,像 devshell 中的会在打包的时候,将ssh key拷贝进来
274
- contentdir = fs.mkdtempSync(path.join(tempDir, "fake-contentdir"))
275
- }
276
-
277
- // 开始打包 contentdir
278
- if (this.beforeTarContentFn.length > 0) {
279
- await this.beforeTarContentFn.reduce(async (prev, curr) => {
280
- let _prev = await prev
281
- await curr(_prev, this.options)
282
- return _prev
283
- }, contentdir)
284
- }
285
- await tarContentDir(["./"], path.join(tempDir, "content.tar"), contentdir)
286
-
287
- // 如果是临时的 contentdir, 目录在打包完成后删除
288
- if (!this.options["contentdir"]) {
289
- fs.rmSync(contentdir, { recursive: true })
290
- }
291
-
292
- if (browserExtension) {
293
- browserExtension = path.resolve(this.pwd, browserExtension)
294
-
295
- if (isDirSync(browserExtension)) {
296
- // 开始打包 browserExtensionDir,这里打包成 zip 包
297
- await archiveFolderTo(
298
- browserExtension,
299
- path.join(tempDir, "extension.zip")
300
- )
301
- } else if (isFileExist(browserExtension)) {
302
- fs.copyFileSync(browserExtension, path.join(tempDir, "extension.zip"))
303
- } else {
304
- throw `${browserExtension} 不存在`
305
- }
306
- }
307
-
308
- if (aiPodService) {
309
- aiPodService = path.resolve(this.pwd, aiPodService)
310
- if (!isDirExist(aiPodService)) {
311
- throw `${aiPodService} 不存在`
312
- }
313
- fs.cpSync(aiPodService, path.join(tempDir, "ai-pod-service"), {
314
- recursive: true
315
- })
316
- }
317
-
318
- // 开始生成 manifest.yml
319
- let manifest = await this.getManifest()
320
- if (process.env.LZC_VERSION) {
321
- manifest.version = process.env.LZC_VERSION
322
- }
323
- if (this.beforeDumpYamlFn.length > 0) {
324
- manifest = await this.beforeDumpYamlFn.reduce(async (prev, curr) => {
325
- return await curr(await prev, this.options)
326
- }, manifest)
327
- }
328
-
329
- if (process.env.LZC_MANIFEST_TEMPLATE) {
330
- logger.debug("copy origin manifest\n", this.manifestFilePath)
331
- fs.copyFileSync(
332
- this.manifestFilePath,
333
- path.join(tempDir, "manifest.yml")
334
- )
335
- } else {
336
- logger.debug("manifest\n", manifest)
337
- // 异常的manifest,就将源文件给转到lpk内
338
- if (this.excpManifest) {
339
- fs.writeFileSync(path.join(tempDir, "manifest.yml"), fs.readFileSync(this.manifestFilePath, "utf8"))
340
- } else {
341
- dumpToYaml(manifest, path.join(tempDir, "manifest.yml"))
342
- }
343
- }
344
-
345
- // compose.override.yml
346
- if (this.options["compose_override"]) {
347
- dumpToYaml(
348
- this.options["compose_override"],
349
- path.join(tempDir, "compose.override.yml")
350
- )
351
- }
352
-
353
- // 打包 lpk
354
- if (this.beforeDumpLpkFn.length > 0) {
355
- await this.beforeDumpLpkFn.reduce(async (prev, curr) => {
356
- await curr(this.options, this.pwd, tempDir)
357
- return prev
358
- }, {})
359
- }
360
-
361
- if (!packName) {
362
- packName = path.resolve(
363
- pkgout,
364
- `${manifest.package}-v${manifest.version}.lpk`
365
- )
366
- }
367
-
368
- const lpkPath = await archiveFolderTo(tempDir, packName)
369
- logger.info(`输出lpk包 ${lpkPath.path}`)
370
-
371
- return lpkPath.path
372
- } finally {
373
- fs.rmSync(tempDir, { recursive: true })
374
- }
375
- }
155
+ constructor(cwd, buildConfigFile) {
156
+ this.pwd = cwd ?? process.cwd();
157
+
158
+ this.optionsFilePath = path.join(this.pwd, buildConfigFile);
159
+ this.options = loadFromYaml(this.optionsFilePath);
160
+
161
+ this.manifestFilePath = this.options['manifest'] ? path.join(this.pwd, this.options['manifest']) : path.join(this.pwd, 'lzc-manifest.yml');
162
+ this.manifest = null;
163
+
164
+ this.beforeBuildPackageFn = [];
165
+ this.beforeDumpYamlFn = [];
166
+ this.beforeTarContentFn = [];
167
+ this.beforeDumpLpkFn = [fetchIconTo, fetchLzcDeployParamTo];
168
+ }
169
+
170
+ // init 时替换 lzc-build.yml 中的模板字段
171
+ async init() {
172
+ const manifest = await this.getManifest();
173
+ const primitive = convenientEnv();
174
+ this.options = yaml.load(await envTemplateFile(this.optionsFilePath, Object.assign({}, primitive, manifest)));
175
+ return this;
176
+ }
177
+
178
+ // onBeforeDumpYaml
179
+ // fn: function(manifest, options) => manifest
180
+ onBeforeDumpYaml(fn) {
181
+ this.beforeDumpYamlFn.push(fn);
182
+ }
183
+ // onBeforeTarContent
184
+ // fn: function(contentdir, options) => void
185
+ onBeforeTarContent(fn) {
186
+ this.beforeTarContentFn.push(fn);
187
+ }
188
+ // onBeforeBuildPackage
189
+ // fn: function(options) => options
190
+ onBeforeBuildPackage(fn) {
191
+ this.beforeBuildPackageFn.push(fn);
192
+ }
193
+
194
+ // onBeforeDumpLpk
195
+ // fn: function(options, cwd, dir) => void
196
+ onBeforeDumpLpk(fn) {
197
+ this.beforeDumpLpkFn.push(fn);
198
+ }
199
+
200
+ async getManifest() {
201
+ if (this.manifest) {
202
+ return this.manifest;
203
+ }
204
+
205
+ let lpkM = new LpkManifest();
206
+ await lpkM.init(this.manifestFilePath);
207
+ this.manifest = lpkM.manifest;
208
+ // manifest使用 text/template模板时,标记为异常manifest
209
+ // 创建lpk时,直接将源文件拷入 lpk
210
+ this.excpManifest = lpkM.excpManifest;
211
+
212
+ if (!isValidPackageName(this.manifest['package'])) {
213
+ throw t('lzc_cli.lib.app.lpk_build.get_manifest_package_name_fail', `{{package}} 含有非法字符,请使用正确的包名格式(java的包名格式),如:cloud.lazycat.apps.video`, {
214
+ package: this.manifest['package'],
215
+ });
216
+ }
217
+
218
+ if (!this.manifest['application']['subdomain']) {
219
+ throw t('lzc_cli.lib.app.lpk_build.get_manifest_subdomain_empty', `application 模块下的 subdomain 字段不能为空`);
220
+ }
221
+
222
+ return this.manifest;
223
+ }
224
+
225
+ async exec() {
226
+ if (this.beforeBuildPackageFn.length > 0) {
227
+ this.options = await this.beforeBuildPackageFn.reduce(async (prev, curr) => {
228
+ return await curr(await prev);
229
+ }, this.options);
230
+ }
231
+
232
+ if (this.options['buildscript']) {
233
+ const cmd = isWindows ? 'cmd' : 'sh';
234
+ const cmdArgs = isWindows ? '/c' : '-c';
235
+ let p = spawn.sync(cmd, [cmdArgs, this.options['buildscript']], {
236
+ cwd: this.pwd,
237
+ stdio: 'inherit',
238
+ });
239
+ if (p.status != 0) {
240
+ throw t('lzc_cli.lib.app.lpk_build.exec_build_fail', `构建失败`);
241
+ }
242
+ } else {
243
+ logger.warn(t('lzc_cli.lib.app.lpk_build.exec_skip_buildscript', '跳过执行 buildscript'));
244
+ }
245
+
246
+ // 输出路径
247
+ let packName = this.options['lpkPath'];
248
+ const pkgout = path.resolve(this.pwd, this.options['pkgout']);
249
+ if (!packName && !isDirExist(pkgout)) {
250
+ throw t('lzc_cli.lib.app.lpk_build.exec_pkgout_not_exist', `{{pkgout}} 不存在`, { pkgout });
251
+ }
252
+
253
+ const tempDir = fs.mkdtempSync('.lzc-cli-build');
254
+ let contentdir = this.options['contentdir'];
255
+ let browserExtension = this.options['browser-extension'];
256
+ let aiPodService = this.options['ai-pod-service'];
257
+ try {
258
+ if (contentdir) {
259
+ contentdir = path.resolve(this.pwd, contentdir);
260
+ if (!isDirExist(contentdir)) {
261
+ throw `${contentdir} 不存在`;
262
+ }
263
+ } else {
264
+ logger.warn(t('lzc_cli.lib.app.lpk_build.exec_skip_copy_contentdir', '跳过拷贝 contentdir 内容'));
265
+ // 当没有指定的 contentdir 的时候,也生成一个空的文件夹
266
+ // 原因是:可能其他地方会复制内容进来,像 devshell 中的会在打包的时候,将ssh key拷贝进来
267
+ contentdir = fs.mkdtempSync(path.join(tempDir, 'fake-contentdir'));
268
+ }
269
+
270
+ // 开始打包 contentdir
271
+ if (this.beforeTarContentFn.length > 0) {
272
+ await this.beforeTarContentFn.reduce(async (prev, curr) => {
273
+ let _prev = await prev;
274
+ await curr(_prev, this.options);
275
+ return _prev;
276
+ }, contentdir);
277
+ }
278
+ await tarContentDir(['./'], path.join(tempDir, 'content.tar'), contentdir);
279
+
280
+ // 如果是临时的 contentdir, 目录在打包完成后删除
281
+ if (!this.options['contentdir']) {
282
+ fs.rmSync(contentdir, { recursive: true });
283
+ }
284
+
285
+ if (browserExtension) {
286
+ browserExtension = path.resolve(this.pwd, browserExtension);
287
+
288
+ if (isDirSync(browserExtension)) {
289
+ // 开始打包 browserExtensionDir,这里打包成 zip 包
290
+ await archiveFolderTo(browserExtension, path.join(tempDir, 'extension.zip'));
291
+ } else if (isFileExist(browserExtension)) {
292
+ fs.copyFileSync(browserExtension, path.join(tempDir, 'extension.zip'));
293
+ } else {
294
+ throw t('lzc_cli.lib.app.lpk_build.exec_browser_extension_not_exist', `{{browserExtension}} 不存在`, { browserExtension });
295
+ }
296
+ }
297
+
298
+ if (aiPodService) {
299
+ aiPodService = path.resolve(this.pwd, aiPodService);
300
+ if (!isDirExist(aiPodService)) {
301
+ throw t('lzc_cli.lib.app.lpk_build.exec_ai_pos_service_not_exist', `{{aiPodService}} 不存在`, {
302
+ aiPodService,
303
+ });
304
+ }
305
+ fs.cpSync(aiPodService, path.join(tempDir, 'ai-pod-service'), {
306
+ recursive: true,
307
+ });
308
+ }
309
+
310
+ // 开始生成 manifest.yml
311
+ let manifest = await this.getManifest();
312
+ if (process.env.LZC_VERSION) {
313
+ manifest.version = process.env.LZC_VERSION;
314
+ }
315
+ if (this.beforeDumpYamlFn.length > 0) {
316
+ manifest = await this.beforeDumpYamlFn.reduce(async (prev, curr) => {
317
+ return await curr(await prev, this.options);
318
+ }, manifest);
319
+ }
320
+
321
+ if (process.env.LZC_MANIFEST_TEMPLATE) {
322
+ logger.debug('copy origin manifest\n', this.manifestFilePath);
323
+ fs.copyFileSync(this.manifestFilePath, path.join(tempDir, 'manifest.yml'));
324
+ } else {
325
+ logger.debug('manifest\n', manifest);
326
+ // 异常的manifest,就将源文件给转到lpk内
327
+ if (this.excpManifest) {
328
+ fs.writeFileSync(path.join(tempDir, 'manifest.yml'), fs.readFileSync(this.manifestFilePath, 'utf8'));
329
+ } else {
330
+ dumpToYaml(manifest, path.join(tempDir, 'manifest.yml'));
331
+ }
332
+ }
333
+
334
+ // compose.override.yml
335
+ if (this.options['compose_override']) {
336
+ dumpToYaml(this.options['compose_override'], path.join(tempDir, 'compose.override.yml'));
337
+ }
338
+
339
+ // 打包 lpk
340
+ if (this.beforeDumpLpkFn.length > 0) {
341
+ await this.beforeDumpLpkFn.reduce(async (prev, curr) => {
342
+ await curr(this.options, this.pwd, tempDir);
343
+ return prev;
344
+ }, {});
345
+ }
346
+
347
+ if (!packName) {
348
+ packName = path.resolve(pkgout, `${manifest.package}-v${manifest.version}.lpk`);
349
+ }
350
+
351
+ const lpkPath = await archiveFolderTo(tempDir, packName);
352
+ logger.info(t('lzc_cli.lib.app.lpk_build.exec_output_lpk_path', `输出lpk包 {{lpkPathStr}}`, { lpkPathStr: lpkPath.path }));
353
+
354
+ return lpkPath.path;
355
+ } finally {
356
+ fs.rmSync(tempDir, { recursive: true });
357
+ }
358
+ }
376
359
  }