• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const fs = require('fs');
17const path = require('path');
18const cluster = require('cluster');
19const process = require('process');
20const crypto = require('crypto');
21const events = require('events');
22const os = require('os');
23const childProcess = require('child_process');
24
25const forward = '(global.___mainEntry___ = function (globalObjects) {' + '\n' +
26              '  var define = globalObjects.define;' + '\n' +
27              '  var require = globalObjects.require;' + '\n' +
28              '  var bootstrap = globalObjects.bootstrap;' + '\n' +
29              '  var register = globalObjects.register;' + '\n' +
30              '  var render = globalObjects.render;' + '\n' +
31              '  var $app_define$ = globalObjects.$app_define$;' + '\n' +
32              '  var $app_bootstrap$ = globalObjects.$app_bootstrap$;' + '\n' +
33              '  var $app_require$ = globalObjects.$app_require$;' + '\n' +
34              '  var history = globalObjects.history;' + '\n' +
35              '  var Image = globalObjects.Image;' + '\n' +
36              '  var OffscreenCanvas = globalObjects.OffscreenCanvas;' + '\n' +
37              '  (function(global) {' + '\n' +
38              '    "use strict";' + '\n';
39const last = '\n' + '})(this.__appProto__);' + '\n' + '})';
40const genAbcScript = 'gen-abc.js';
41let output;
42let isWin = false;
43let isMac = false;
44let isDebug = false;
45let arkDir;
46let nodeJs;
47let intermediateJsBundle = [];
48let workerFile = null;
49let fileterIntermediateJsBundle = [];
50let hashJsonObject = {};
51let buildPathInfo = "";
52const SUCCESS = 0;
53const FAIL = 1;
54const red = '\u001b[31m';
55const reset = '\u001b[39m';
56const blue = '\u001b[34m';
57const hashFile = 'gen_hash.json';
58const ARK = '/ark/';
59const NODE_MODULES = 'node_modules';
60const TEMPORARY = 'temporary';
61const TS2ABC = 'ts2abc';
62const ES2ABC = 'es2abc';
63const WINDOWS = 'Windows_NT';
64const LINUX = 'Linux';
65const MAC = 'Darwin';
66const FILESINFO_TXT = 'filesInfo.txt';
67const manageBunldeWorkersScript = 'manage-bundle-workers.js';
68const PREBUILDINFO_JSON = 'preBuildInfo.json';
69
70class GenAbcPlugin {
71  constructor(output_, arkDir_, nodeJs_, workerFile_, isDebug_) {
72    output = output_;
73    arkDir = arkDir_;
74    nodeJs = nodeJs_;
75    isDebug = isDebug_;
76    workerFile = workerFile_;
77  }
78  apply(compiler) {
79    if (fs.existsSync(path.resolve(arkDir, 'build-win'))) {
80      isWin = true;
81    } else if (fs.existsSync(path.resolve(arkDir, 'build-mac'))) {
82      isMac = true;
83    } else if (!fs.existsSync(path.resolve(arkDir, 'build'))) {
84      console.error(red, 'ERROR find build fail', reset);
85      process.exitCode = FAIL;
86      return;
87    }
88
89    if (!checkNodeModules()) {
90      process.exitCode = FAIL;
91      return;
92    }
93
94    // for preview mode max listeners
95    events.EventEmitter.defaultMaxListeners = 100;
96
97    compiler.hooks.emit.tap('GenAbcPlugin', (compilation) => {
98      const assets = compilation.assets;
99      const keys = Object.keys(assets);
100      buildPathInfo = output;
101      keys.forEach(key => {
102        // choice *.js
103        if (output && path.extname(key) === '.js') {
104          let newContent = assets[key].source();
105          if (checkWorksFile(key, workerFile) && key !== 'commons.js' && key !== 'vendors.js') {
106            newContent = forward + newContent + last;
107          }
108          if (key === 'commons.js' || key === 'vendors.js' || !checkWorksFile(key, workerFile)) {
109            newContent = `\n\n\n\n\n\n\n\n\n\n\n\n\n\n` + newContent;
110          }
111          const keyPath = key.replace(/\.js$/, ".temp.js");
112          writeFileSync(newContent, output, keyPath, key, true);
113        } else if (output && path.extname(key) === '.json' &&
114          process.env.DEVICE_LEVEL === 'card' && process.env.configOutput && !checkI18n(key)) {
115          writeFileSync(assets[key].source(), output, key, key, false);
116        }
117      })
118    });
119    compiler.hooks.afterEmit.tap('GenAbcPluginMultiThread', () => {
120      if (intermediateJsBundle.length === 0) {
121        return;
122      }
123      buildPathInfo = output;
124      clearWebpackCacheByBuildInfo();
125      setPrebuildInfo();
126      processMultiThreadEntry();
127    });
128  }
129}
130
131function processMultiThreadEntry() {
132  if (isTs2Abc() || process.env.minPlatformVersion === "8") {
133      invokeWorkerToGenAbc();
134  } else if (isEs2Abc()) {
135    generateAbcByEs2AbcOfBundleMode(intermediateJsBundle);
136  } else {
137    console.debug(red, `ERROR please set panda module`, reset);
138  }
139}
140
141function checkI18n(key) {
142  const outI18nPath = path.resolve(process.env.configOutput, key);
143  const projectI18nPath = outI18nPath.replace(output, process.env.projectPath);
144  if (projectI18nPath.indexOf(
145    path.resolve(__dirname, process.env.projectPath, 'i18n')) > -1) {
146    return true;
147  }
148  return false;
149}
150
151function checkWorksFile(assetPath, workerFile) {
152  if (workerFile === null) {
153    if (assetPath.search("./workers/") !== 0) {
154      return true;
155    } else {
156      return false;
157    }
158  } else {
159    for (const key in workerFile) {
160      let keyExt = key + '.js';
161      if (keyExt === assetPath) {
162        return false;
163      }
164    }
165  }
166
167  return true;
168}
169
170function writeFileSync(inputString, buildPath, keyPath, jsBundleFile, isToBin) {
171    let output = path.resolve(buildPath, keyPath);
172    validateFilePathLength(output);
173    let parent = path.join(output, '..');
174    if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
175        mkDir(parent);
176    }
177    if (!isToBin) {
178      fs.writeFileSync(output, inputString);
179      return;
180    }
181    let cacheOutputPath = "";
182    if (process.env.cachePath) {
183      let buildDirArr = buildPathInfo.split(path.sep);
184      let abilityDir = buildDirArr[buildDirArr.length - 1];
185      cacheOutputPath = path.join(process.env.cachePath, TEMPORARY, abilityDir, keyPath);
186    } else {
187      cacheOutputPath = output;
188    }
189    validateFilePathLength(cacheOutputPath);
190    parent = path.join(cacheOutputPath, '..');
191    if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
192      mkDir(parent);
193    }
194    fs.writeFileSync(cacheOutputPath, inputString);
195    if (fs.existsSync(cacheOutputPath)) {
196      let fileSize = fs.statSync(cacheOutputPath).size;
197      let sourceFile = output.replace(/\.temp\.js$/, "_.js");
198      if (!isDebug && (process.env.aceBuildJson && fs.existsSync(process.env.aceBuildJson))) {
199        const buildJsonInfo = JSON.parse(fs.readFileSync(process.env.aceBuildJson).toString());
200        sourceFile = toUnixPath(sourceFile.replace(buildJsonInfo.projectRootPath + path.sep, ''));
201      } else {
202        sourceFile = toUnixPath(sourceFile);
203      }
204      output = toUnixPath(output);
205      cacheOutputPath = toUnixPath(cacheOutputPath);
206      intermediateJsBundle.push({
207        path: output, size: fileSize, cacheOutputPath: cacheOutputPath, sourceFile: sourceFile
208      });
209    } else {
210      console.debug(red, `ERROR Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, reset);
211      process.exitCode = FAIL;
212    }
213}
214
215function mkDir(path_) {
216    const parent = path.join(path_, '..');
217    if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
218        mkDir(parent);
219    }
220    fs.mkdirSync(path_);
221}
222
223function getSmallestSizeGroup(groupSize) {
224  let groupSizeArray = Array.from(groupSize);
225  groupSizeArray.sort(function(g1, g2) {
226    return g1[1] - g2[1]; // sort by size
227  });
228  return groupSizeArray[0][0];
229}
230
231function splitJsBundlesBySize(bundleArray, groupNumber) {
232  let result = [];
233  if (bundleArray.length < groupNumber) {
234    for (let value of bundleArray) {
235      result.push([value]);
236    }
237    return result;
238  }
239
240  bundleArray.sort(function(f1, f2) {
241    return f2.size - f1.size;
242  });
243  let groupFileSize = new Map();
244  for (let i = 0; i < groupNumber; ++i) {
245    result.push([]);
246    groupFileSize.set(i, 0);
247  }
248
249  let index = 0;
250  while(index < bundleArray.length) {
251    let smallestGroup = getSmallestSizeGroup(groupFileSize);
252    result[smallestGroup].push(bundleArray[index]);
253    let sizeUpdate = groupFileSize.get(smallestGroup) + bundleArray[index].size;
254    groupFileSize.set(smallestGroup, sizeUpdate);
255    index++;
256  }
257  return result;
258}
259
260function invokeWorkerToGenAbc() {
261  if (process.env.isPreview === "true") {
262    process.exitCode = SUCCESS;
263  }
264  let maxWorkerNumber = isEs2Abc() ? os.cpus().length : 3;
265  const abcArgs = initAbcEnv();
266  let cmdPrefix = initCmdPrefix(abcArgs);
267
268  filterIntermediateJsBundleByHashJson(buildPathInfo, intermediateJsBundle);
269  const splitedBundles = splitJsBundlesBySize(fileterIntermediateJsBundle, maxWorkerNumber);
270  const workerNumber = maxWorkerNumber < splitedBundles.length ? maxWorkerNumber : splitedBundles.length;
271
272  try  {
273    if (process.env.isPreview === 'true') {
274      processWorkersOfPreviewMode(splitedBundles, cmdPrefix, workerNumber);
275    } else {
276      processWorkersOfBuildMode(splitedBundles, cmdPrefix, workerNumber);
277    }
278  } catch (e) {
279    console.debug(red, `ERROR failed to generate abc. Error message: ${e} `, reset);
280    process.env.abcCompileSuccess = 'false';
281    if (process.env.isPreview !== 'true') {
282      process.exit(FAIL);
283    }
284  }
285}
286
287function clearGlobalInfo() {
288  if (process.env.isPreview !== "true") {
289    intermediateJsBundle = [];
290  }
291  fileterIntermediateJsBundle = [];
292  hashJsonObject = {};
293}
294
295function filterIntermediateJsBundleByHashJson(buildPath, inputPaths) {
296  inputPaths = removeDuplicateInfoOfBundleList(inputPaths);
297
298  for (let i = 0; i < inputPaths.length; ++i) {
299    fileterIntermediateJsBundle.push(inputPaths[i]);
300  }
301  const hashFilePath = genHashJsonPath(buildPath);
302  if (hashFilePath.length == 0) {
303    return;
304  }
305  let updateJsonObject = {};
306  let jsonObject = {};
307  let jsonFile = "";
308  if (fs.existsSync(hashFilePath)) {
309    jsonFile = fs.readFileSync(hashFilePath).toString();
310    jsonObject = JSON.parse(jsonFile);
311    fileterIntermediateJsBundle = [];
312    for (let i = 0; i < inputPaths.length; ++i) {
313      const cacheOutputPath = inputPaths[i].cacheOutputPath;
314      const cacheAbcFilePath = cacheOutputPath.replace(/\.temp\.js$/, '.abc');
315      if (!fs.existsSync(cacheOutputPath)) {
316        console.debug(red, `ERROR ${cacheOutputPath} is lost`, reset);
317        process.exitCode = FAIL;
318        break;
319      }
320
321      if (fs.existsSync(cacheAbcFilePath)) {
322        const hashInputContentData = toHashData(cacheOutputPath);
323        const hashAbcContentData = toHashData(cacheAbcFilePath);
324        if (jsonObject[cacheOutputPath] === hashInputContentData && jsonObject[cacheAbcFilePath] === hashAbcContentData) {
325          updateJsonObject[cacheOutputPath] = hashInputContentData;
326          updateJsonObject[cacheAbcFilePath] = hashAbcContentData;
327        } else {
328          fileterIntermediateJsBundle.push(inputPaths[i]);
329        }
330      } else {
331        fileterIntermediateJsBundle.push(inputPaths[i]);
332      }
333    }
334  }
335
336  hashJsonObject = updateJsonObject;
337}
338
339function writeHashJson() {
340  for (let i = 0; i < fileterIntermediateJsBundle.length; ++i) {
341    const cacheOutputPath = fileterIntermediateJsBundle[i].cacheOutputPath;
342    const cacheAbcFilePath = cacheOutputPath.replace(/\.temp\.js$/, '.abc');
343    if (!fs.existsSync(cacheOutputPath) || !fs.existsSync(cacheAbcFilePath)) {
344      console.debug(red, `ERROR ${cacheOutputPath} is lost`, reset);
345      process.exitCode = FAIL;
346      break;
347    }
348    const hashInputContentData = toHashData(cacheOutputPath);
349    const hashAbcContentData = toHashData(cacheAbcFilePath);
350    hashJsonObject[cacheOutputPath] = hashInputContentData;
351    hashJsonObject[cacheAbcFilePath] = hashAbcContentData;
352  }
353  const hashFilePath = genHashJsonPath(buildPathInfo);
354  if (hashFilePath.length == 0) {
355    return;
356  }
357  fs.writeFileSync(hashFilePath, JSON.stringify(hashJsonObject));
358}
359
360function genHashJsonPath(buildPath) {
361  buildPath = toUnixPath(buildPath);
362  if (process.env.cachePath) {
363    if (!fs.existsSync(process.env.cachePath) || !fs.statSync(process.env.cachePath).isDirectory()) {
364      return '';
365    }
366    let buildDirArr = buildPathInfo.split(path.sep);
367    let abilityDir = buildDirArr[buildDirArr.length - 1];
368    let hashJsonPath = path.join(process.env.cachePath, TEMPORARY, abilityDir, hashFile);
369    validateFilePathLength(hashJsonPath);
370    let parent = path.join(hashJsonPath, '..');
371    if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
372      mkDir(parent);
373    }
374    return hashJsonPath;
375  } else if (buildPath.indexOf(ARK) >= 0) {
376    const dataTmps = buildPath.split(ARK);
377    const hashPath = path.join(dataTmps[0], ARK);
378    if (!fs.existsSync(hashPath) || !fs.statSync(hashPath).isDirectory()) {
379      return '';
380    }
381    let hashJsonPath = path.join(hashPath, hashFile);
382    validateFilePathLength(hashJsonPath);
383    return hashJsonPath;
384  } else {
385    return '';
386  }
387}
388
389function toUnixPath(data) {
390  if (/^win/.test(require('os').platform())) {
391    const fileTmps = data.split(path.sep);
392    const newData = path.posix.join(...fileTmps);
393    return newData;
394  }
395  return data;
396}
397
398function toHashData(path) {
399  const content = fs.readFileSync(path);
400  const hash = crypto.createHash('sha256');
401  hash.update(content);
402  return hash.digest('hex');
403}
404
405module.exports = {
406  GenAbcPlugin: GenAbcPlugin,
407  checkWorksFile: checkWorksFile
408}
409
410function copyFileCachePathToBuildPath() {
411  for (let i = 0; i < intermediateJsBundle.length; ++i) {
412    const abcFile = intermediateJsBundle[i].path.replace(/\.temp\.js$/, ".abc");
413    const cacheOutputPath = intermediateJsBundle[i].cacheOutputPath;
414    const cacheAbcFilePath = intermediateJsBundle[i].cacheOutputPath.replace(/\.temp\.js$/, ".abc");
415    if (!fs.existsSync(cacheAbcFilePath)) {
416      console.debug(red, `ERROR ${cacheAbcFilePath} is lost`, reset);
417      process.exitCode = FAIL;
418      break;
419    }
420    let parent = path.join(abcFile, '..');
421    if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
422      mkDir(parent);
423    }
424    // for preview mode, cache path and old abc file both exist, should copy abc file for updating
425    if (process.env.cachePath !== undefined) {
426      fs.copyFileSync(cacheAbcFilePath, abcFile);
427    }
428    if (process.env.cachePath === undefined && fs.existsSync(cacheOutputPath)) {
429      fs.unlinkSync(cacheOutputPath);
430    }
431  }
432}
433
434function processExtraAssetForBundle() {
435  writeHashJson();
436  copyFileCachePathToBuildPath();
437  clearGlobalInfo();
438}
439
440function checkNodeModules() {
441  if (process.env.panda === TS2ABC) {
442    let arkEntryPath = path.join(arkDir, 'build');
443    if (isWin) {
444      arkEntryPath = path.join(arkDir, 'build-win');
445    } else if (isMac) {
446      arkEntryPath = path.join(arkDir, 'build-mac');
447    }
448    let nodeModulesPath = path.join(arkEntryPath, NODE_MODULES);
449    validateFilePathLength(nodeModulesPath);
450    if (!(fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory())) {
451      console.error(red, `ERROR: node_modules for ark compiler not found.
452        Please make sure switch to non-root user before runing "npm install" for safity requirements and try re-run "npm install" under ${arkEntryPath}`, reset);
453      return false;
454    }
455  }
456
457  return true;
458}
459
460function initAbcEnv() {
461  let args = [];
462  if (process.env.minPlatformVersion === "8") {
463    process.env.panda = TS2ABC;
464    let js2abc = path.join(arkDir, 'build', 'legacy_api8', 'src', 'index.js');
465    if (isWin) {
466      js2abc = path.join(arkDir, 'build-win', 'legacy_api8', 'src', 'index.js');
467    } else if (isMac) {
468      js2abc = path.join(arkDir, 'build-mac', 'legacy_api8', 'src', 'index.js');
469    }
470    validateFilePathLength(js2abc);
471
472    js2abc = '"' + js2abc + '"';
473    args = [
474      '--expose-gc',
475      js2abc
476    ];
477    if (isDebug) {
478      args.push('--debug');
479    }
480  } else if (process.env.panda === TS2ABC) {
481    let js2abc = path.join(arkDir, 'build', 'src', 'index.js');
482    if (isWin) {
483      js2abc = path.join(arkDir, 'build-win', 'src', 'index.js');
484    } else if (isMac) {
485      js2abc = path.join(arkDir, 'build-mac', 'src', 'index.js');
486    }
487    validateFilePathLength(js2abc);
488
489    js2abc = '"' + js2abc + '"';
490    args = [
491      '--expose-gc',
492      js2abc
493    ];
494    if (isDebug) {
495      args.push('--debug');
496    }
497  } else if (process.env.panda === ES2ABC  || process.env.panda === 'undefined' || process.env.panda === undefined) {
498    let es2abc = path.join(arkDir, 'build', 'bin', 'es2abc');
499    if (isWin) {
500      es2abc = path.join(arkDir, 'build-win', 'bin', 'es2abc.exe');
501    } else if (isMac) {
502      es2abc = path.join(arkDir, 'build-mac', 'bin', 'es2abc');
503    }
504    validateFilePathLength(es2abc);
505
506    args = [
507      '"' + es2abc + '"'
508    ];
509    if (isDebug) {
510      args.push('--debug-info');
511    }
512  }  else {
513    console.debug(red, `ERROR: please set panda module`, reset);
514  }
515
516  return args;
517}
518
519export function isWindows() {
520  return os.type() === WINDOWS;
521}
522
523export function isLinux() {
524  return os.type() === LINUX;
525}
526
527export function isMacOs() {
528  return os.type() === MAC;
529}
530
531export function maxFilePathLength() {
532  if (isWindows()) {
533    return 32766;
534  } else if (isLinux()) {
535    return 4095;
536  } else if (isMacOs()) {
537    return 1016;
538  } else {
539    return -1;
540  }
541}
542
543export function validateFilePathLength(filePath) {
544  if (maxFilePathLength() < 0) {
545    console.error("Unknown OS platform");
546    process.exitCode = FAIL;
547    return false;
548  } else if (filePath.length > 0 && filePath.length <= maxFilePathLength()) {
549    return true;
550  } else if (filePath.length > maxFilePathLength()) {
551    console.error(`The length of ${filePath} exceeds the limitation of current platform, which is ` +
552    `${maxFilePathLength()}. Please try moving the project folder to avoid deeply nested file path and try again`);
553    process.exitCode = FAIL;
554    return false;
555  } else {
556    console.error("Validate file path failed");
557    process.exitCode = FAIL;
558    return false;
559  }
560}
561
562export function isEs2Abc() {
563  return process.env.panda === ES2ABC  || process.env.panda === 'undefined' || process.env.panda === undefined;
564}
565
566export function isTs2Abc() {
567  return process.env.panda === TS2ABC;
568}
569
570function generateAbcByEs2AbcOfBundleMode(inputPaths) {
571  filterIntermediateJsBundleByHashJson(buildPathInfo, inputPaths);
572  if (fileterIntermediateJsBundle.length === 0) {
573    processExtraAssetForBundle();
574    return;
575  }
576  let filesInfoPath = generateFileOfBundle(fileterIntermediateJsBundle);
577  const fileThreads = os.cpus().length < 16 ? os.cpus().length : 16;
578  let genAbcCmd =
579      `${initAbcEnv().join(' ')} "@${filesInfoPath}" --file-threads "${fileThreads}"`;
580
581  console.debug('gen abc cmd is: ', genAbcCmd);
582  try {
583    if (process.env.isPreview === 'true') {
584      childProcess.execSync(genAbcCmd);
585      processExtraAssetForBundle();
586    } else {
587      const child = childProcess.exec(genAbcCmd);
588      child.on('exit', (code) => {
589        if (code === FAIL) {
590          console.debug(red, "ERROR failed to execute es2abc", reset);
591          process.exit(FAIL);
592        }
593        if (process.env.cachePath === undefined) {
594          unlinkSync(filesInfoPath);
595        }
596        processExtraAssetForBundle();
597      });
598
599      child.on('error', (err) => {
600        console.debug(red, err.toString(), reset);
601        process.exit(FAIL);
602      });
603
604      child.stderr.on('data', (data) => {
605        console.debug(red, data.toString(), reset);
606      });
607    }
608  } catch (e) {
609    console.debug(red, `ERROR failed to generate abc with filesInfo ${filesInfoPath}. Error message: ${e} `, reset);
610    process.env.abcCompileSuccess = 'false';
611    if (process.env.isPreview !== 'true') {
612      process.exit(FAIL);
613    }
614  } finally {
615    if (process.env.isPreview === 'true') {
616      if (process.env.cachePath === undefined) {
617        unlinkSync(filesInfoPath);
618      }
619    }
620  }
621}
622
623function generateFileOfBundle(inputPaths) {
624  let filesInfoPath = buildCachePath(FILESINFO_TXT);
625  inputPaths = removeDuplicateInfoOfBundleList(inputPaths);
626
627  let filesInfo = '';
628  inputPaths.forEach(info => {
629    const cacheOutputPath = info.cacheOutputPath;
630    const recordName = 'null_recordName';
631    const moduleType = 'script';
632    const sourceFile = info.sourceFile;
633    const abcFilePath = cacheOutputPath.replace(/\.temp\.js$/, ".abc");
634    filesInfo += `${cacheOutputPath};${recordName};${moduleType};${sourceFile};${abcFilePath}\n`;
635  });
636  fs.writeFileSync(filesInfoPath, filesInfo, 'utf-8');
637
638  return filesInfoPath;
639}
640
641function removeDuplicateInfoOfBundleList(inputPaths) {
642  let tempInputPaths = [];
643  inputPaths.forEach((item) => {
644    const check = tempInputPaths.every((newItem) => {
645      return item.path !== newItem.path;
646    });
647    if (check) {
648      tempInputPaths.push(item);
649    }
650  });
651  inputPaths = tempInputPaths;
652
653  return inputPaths;
654}
655
656function buildCachePath(tailName) {
657  let pathName = process.env.cachePath !== undefined ?
658      path.join(process.env.cachePath, tailName) : path.join(buildPathInfo, tailName);
659  validateFilePathLength(pathName);
660
661  return pathName;
662}
663
664function unlinkSync(filePath) {
665  if (fs.existsSync(filePath)) {
666    fs.unlinkSync(filePath);
667  }
668}
669
670function initCmdPrefix(abcArgs) {
671  let cmdPrefix = "";
672  if (process.env.panda === TS2ABC) {
673    cmdPrefix = `${nodeJs} ${abcArgs.join(' ')}`;
674  } else if (process.env.panda === ES2ABC  || process.env.panda === 'undefined' || process.env.panda === undefined) {
675    cmdPrefix = `${abcArgs.join(' ')}`;
676  } else {
677    console.debug(red, `ERROR please set panda module`, reset);
678  }
679
680  return cmdPrefix;
681}
682
683function processWorkersOfPreviewMode(splittedData, cmdPrefix, workerNumber) {
684  let processEnv = Object.assign({}, process.env);
685  let arkEnvParams = {
686    'splittedData': JSON.stringify(splittedData),
687    'cmdPrefix': cmdPrefix,
688    'workerNumber': workerNumber.toString()
689  };
690  processEnv.arkEnvParams = JSON.stringify(arkEnvParams);
691
692  let genAbcCmd = `${nodeJs} "${path.resolve(__dirname, manageBunldeWorkersScript)}"`;
693  childProcess.execSync(genAbcCmd, {env: processEnv});
694  processExtraAssetForBundle();
695}
696
697function processWorkersOfBuildMode(splittedData, cmdPrefix, workerNumber) {
698  const clusterNewApiVersion = 16;
699  const currentNodeVersion = parseInt(process.version.split(".")[0]);
700  const useNewApi = currentNodeVersion >= clusterNewApiVersion;
701
702  if (useNewApi && cluster.isPrimary || !useNewApi && cluster.isMaster) {
703    if (useNewApi) {
704      cluster.setupPrimary({
705        exec: path.resolve(__dirname, genAbcScript)
706      });
707    } else {
708      cluster.setupMaster({
709        exec: path.resolve(__dirname, genAbcScript)
710      });
711    }
712
713    for (let i = 0; i < workerNumber; ++i) {
714      let workerData = {
715        'inputs': JSON.stringify(splittedData[i]),
716        'cmd': cmdPrefix
717      };
718      cluster.fork(workerData);
719    }
720
721    cluster.on('exit', (worker, code, signal) => {
722      if (code === FAIL) {
723        process.exitCode = FAIL;
724      }
725      console.debug(`worker ${worker.process.pid} finished`);
726    });
727
728    process.on('exit', (code) => {
729      if (process.exitCode !== FAIL && process.env.isPreview !== 'true') {
730        processExtraAssetForBundle();
731      }
732    });
733  }
734}
735
736function clearWebpackCacheByBuildInfo() {
737  if (!process.env.cachePath) {
738    return;
739  }
740
741  // clear&update cache dir when build info is different from last time
742  const cachePrebuildInfoPath = path.join(process.env.cachePath, PREBUILDINFO_JSON);
743  if (fs.existsSync(cachePrebuildInfoPath)) {
744    let cachedJson = undefined;
745    try {
746      cachedJson = JSON.parse(fs.readFileSync(cachePrebuildInfoPath).toString());
747    } catch {
748      removeHashJsonFile();
749      return;
750    }
751    // api version is 8 or 9
752    if (cachedJson && cachedJson.minAPIVersion &&
753      cachedJson.minAPIVersion.toString() !== process.env.minPlatformVersion) {
754      removeHashJsonFile();
755    }
756  }
757}
758
759function setPrebuildInfo() {
760  if (process.env.cachePath && process.env.minPlatformVersion) {
761    let cachedJson = {};
762    const cachePrebuildInfoPath = path.join(process.env.cachePath, PREBUILDINFO_JSON);
763    validateFilePathLength(cachePrebuildInfoPath);
764    cachedJson.minAPIVersion = process.env.minPlatformVersion;
765    fs.writeFile(cachePrebuildInfoPath, JSON.stringify(cachedJson, null, 2), 'utf-8',
766      (err) => {
767        if (err) {
768          logger.error(red, `ArkTS:ERROR Failed to write bundle build info.`, reset);
769        }
770      }
771    );
772  }
773}
774
775function removeHashJsonFile() {
776  const hashFilePath = genHashJsonPath(buildPathInfo);
777  if (hashFilePath.length !== 0 && fs.existsSync(hashFilePath)) {
778    fs.unlinkSync(hashFilePath);
779  }
780}
781