1/* 2 * Copyright (c) 2023 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 16import fs from 'fs'; 17import path from 'path'; 18 19import { 20 HASH_FILE_NAME, 21 IS_CACHE_INVALID, 22 GEN_ABC_PLUGIN_NAME, 23 GEN_ABC_SCRIPT, 24 blue, 25 reset, 26 ES2ABC, 27 TS2ABC 28} from './ark_define'; 29import { initArkConfig } from './process_ark_config'; 30import { 31 nodeLargeOrEqualTargetVersion, 32 mkdirsSync, 33 validateFilePathLength 34} from '../../../utils'; 35import { 36 isEs2Abc, 37 isOhModules, 38 isTs2Abc 39} from '../../../ark_utils'; 40import { 41 genTemporaryModuleCacheDirectoryForBundle 42} from '../utils'; 43import { 44 CommonLogger, 45 LogData, 46 LogDataFactory 47} from '../logger'; 48import { 49 ArkTSInternalErrorDescription, 50 ErrorCode 51} from '../error_code'; 52 53export abstract class CommonMode { 54 projectConfig: Object; 55 arkConfig: Object; 56 cmdArgs: string[] = []; 57 logger: CommonLogger; 58 hashJsonFilePath: string; 59 genAbcScriptPath: string; 60 triggerAsync: Object; 61 triggerEndSignal: Object; 62 63 constructor(rollupObject: Object) { 64 this.projectConfig = Object.assign(rollupObject.share.arkProjectConfig, rollupObject.share.projectConfig); 65 this.arkConfig = initArkConfig(this.projectConfig); 66 this.logger = CommonLogger.getInstance(rollupObject); 67 this.cmdArgs = this.initCmdEnv(); 68 this.hashJsonFilePath = this.genHashJsonFilePath(); 69 this.genAbcScriptPath = path.resolve(__dirname, GEN_ABC_SCRIPT); 70 // Each time triggerAsync() was called, IDE will wait for asynchronous operation to finish before continue excuting. 71 // The finish signal was passed to IDE by calling triggerEndSignal() in the child process created by triggerAsync() 72 // When multiple workers were invoked by triggerAsync(), IDE will wait until the times of calling 73 // triggerEndSignal() matches the number of workers invoked. 74 // If the child process throws an error by calling throwArkTsCompilerError(), IDE will reset the counting state. 75 this.triggerAsync = rollupObject.async; 76 this.triggerEndSignal = rollupObject.signal; 77 } 78 79 initCmdEnv() { 80 let args: string[] = []; 81 82 if (isTs2Abc(this.projectConfig)) { 83 let ts2abc: string = this.arkConfig.ts2abcPath; 84 validateFilePathLength(ts2abc, this.logger); 85 86 ts2abc = '"' + ts2abc + '"'; 87 args = [`${this.arkConfig.nodePath}`, '--expose-gc', ts2abc]; 88 if (this.arkConfig.isDebug) { 89 args.push('--debug'); 90 } 91 if (isOhModules(this.projectConfig)) { 92 args.push('--oh-modules'); 93 } 94 } else if (isEs2Abc(this.projectConfig)) { 95 const es2abc: string = this.arkConfig.es2abcPath; 96 validateFilePathLength(es2abc, this.logger); 97 98 args = ['"' + es2abc + '"']; 99 // compile options added here affect both bundle mode and module mode 100 if (this.arkConfig.isDebug) { 101 args.push('--debug-info'); 102 } 103 } else { 104 const errInfo: LogData = LogDataFactory.newInstance( 105 ErrorCode.ETS2BUNDLE_INTERNAL_INVALID_COMPILE_MODE, 106 ArkTSInternalErrorDescription, 107 'Invalid compilation mode. ' + 108 `ProjectConfig.pandaMode should be either ${TS2ABC} or ${ES2ABC}.` 109 ); 110 this.logger.printErrorAndExit(errInfo); 111 } 112 113 return args; 114 } 115 116 private genHashJsonFilePath() { 117 if (this.projectConfig.cachePath) { 118 if (!fs.existsSync(this.projectConfig.cachePath) || !fs.statSync(this.projectConfig.cachePath).isDirectory()) { 119 this.logger.debug(blue, `ArkTS:WARN cache path does bit exist or is not directory`, reset); 120 return ''; 121 } 122 const hashJsonPath: string = path.join(genTemporaryModuleCacheDirectoryForBundle(this.projectConfig), HASH_FILE_NAME); 123 validateFilePathLength(hashJsonPath, this.logger); 124 mkdirsSync(path.dirname(hashJsonPath)); 125 return hashJsonPath; 126 } else { 127 this.logger.debug(blue, `ArkTS:WARN cache path not specified`, reset); 128 return ''; 129 } 130 } 131 132 setupCluster(cluster: Object): void { 133 cluster.removeAllListeners('exit'); 134 if (nodeLargeOrEqualTargetVersion(16)) { 135 cluster.setupPrimary({ 136 exec: this.genAbcScriptPath, 137 windowsHide: true 138 }); 139 } else { 140 cluster.setupMaster({ 141 exec: this.genAbcScriptPath, 142 windowsHide: true 143 }); 144 } 145 } 146 147 protected needRemoveCacheInfo(rollupObject: Object): boolean { 148 return rollupObject.cache.get(IS_CACHE_INVALID) || rollupObject.cache.get(IS_CACHE_INVALID) === undefined; 149 } 150 151 protected removeCacheInfo(rollupObject: Object): void { 152 if (this.needRemoveCacheInfo(rollupObject)) { 153 this.removeCompilationCache(); 154 } 155 rollupObject.cache.set(IS_CACHE_INVALID, false); 156 } 157 158 abstract removeCompilationCache(): void; 159} 160