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