1/* 2 * Copyright (c) 2024 - 2025 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 {ArkFile, Scene, SceneConfig} from 'arkanalyzer'; 17import Logger, {LOG_MODULE_TYPE} from 'arkanalyzer/lib/utils/logger'; 18import {buildModuleChains} from './BuildModuleChains'; 19import {ProjectConfig} from '../model/ProjectConfig'; 20import {FileUtils, WriteFileMode} from '../utils/common/FileUtils'; 21import {Utils} from '../utils/common/Utils'; 22import {buildFileDepGraph, buildModuleDepGraph} from './depGraph/builder'; 23import {OptionValues} from 'commander'; 24import {ConfigUtils} from '../Index'; 25import path from 'path'; 26import fs from 'fs'; 27 28const logger = Logger.getLogger(LOG_MODULE_TYPE.TOOL, 'runTool'); 29 30export function runTool(tool: Tools, argvObj: OptionValues): void { 31 const startTime = new Date().getTime(); 32 const projectConfig = new ProjectConfig(ConfigUtils.getConfig(argvObj.projectConfigPath)); 33 let depGraphOutputDir = argvObj.depGraphOutputDir; 34 35 try { 36 // 配置日志文件路径 37 const logPath = projectConfig.logPath; 38 Utils.setLogPath(logPath.length ? logPath : './HomeCheckTools.log'); 39 logger.info('start to run tool...'); 40 const scene = buildScene(projectConfig); 41 if (!scene) { 42 return; 43 } 44 // 运行对应工具模块 45 switch (tool) { 46 case Tools.ImportChains: 47 logger.info('start to buildModuleChains...'); 48 buildModuleChains(scene, [], projectConfig.reportDir); 49 logger.info('buildModuleChains completed.'); 50 break; 51 case Tools.DepGraph: 52 if (!depGraphOutputDir) { 53 logger.warn('The output directory of dependency graph is not set, by default it will be set to current directory.'); 54 depGraphOutputDir = './'; 55 } 56 if (!fs.existsSync(depGraphOutputDir)) { 57 logger.error(`The given depGraphOutputDir: ${depGraphOutputDir} is not exist.`); 58 process.exit(-1); 59 } 60 genFileDepGraph(depGraphOutputDir, scene.getFiles()); 61 genModuleDepGraph(depGraphOutputDir, scene); 62 break; 63 default: 64 logger.error(`Unknown tool: ${tool}`); 65 break; 66 } 67 } catch (error) { 68 logger.error(`Error occurred: ${(error as Error).message}`); 69 return; 70 } 71 const endTime = new Date().getTime(); 72 logger.info(`HomeCheck tools took: ${(endTime - startTime) / 1000}s`); 73} 74 75function buildScene(projectConfig: ProjectConfig): Scene | null { 76 try { 77 // 构建SceneConfig 78 const config: SceneConfig = new SceneConfig(); 79 const fileList = FileUtils.getAllFiles(projectConfig.projectPath, ['.ts', '.ets']); 80 config.buildFromProjectFiles(projectConfig.projectName, projectConfig.projectPath, fileList, FileUtils.genSdks(projectConfig)); 81 logger.info('Build sceneConfig completed.'); 82 // 构建Scene 83 const scene = new Scene(); 84 scene.buildSceneFromFiles(config); 85 logger.info('Build scene completed.'); 86 scene.inferTypes(); 87 logger.info('Infer types completed.'); 88 return scene; 89 } catch (error) { 90 logger.error(`Build scene or infer types error: ${(error as Error).message}`); 91 return null; 92 } 93} 94 95function genFileDepGraph(outputPath: string, arkFiles: ArkFile[]): void { 96 const fileDepGraphJson = path.join(outputPath, './fileDepGraph.json'); 97 const fileDepGraphDot = path.join(outputPath, './fileDepGraph.dot'); 98 99 logger.info('Started to build file dependency graph...'); 100 101 const depGraph = buildFileDepGraph(arkFiles); 102 103 const jsonRes = JSON.stringify(depGraph.toJson()); 104 FileUtils.writeToFile(fileDepGraphJson, jsonRes, WriteFileMode.OVERWRITE); 105 logger.info('Building dependency graph in json format has completed.'); 106 107 const dotRes = depGraph.dump(); 108 FileUtils.writeToFile(fileDepGraphDot, dotRes, WriteFileMode.OVERWRITE); 109 logger.info('Building dependency graph in dot format has completed.'); 110 111 logger.info('Building file dependency graph completed.'); 112} 113 114function genModuleDepGraph(outputPath: string, scene: Scene): void { 115 const moduleDepGraphJson = path.join(outputPath, './moduleDepGraph.json'); 116 const moduleDepGraphDot = path.join(outputPath, './moduleDepGraph.dot'); 117 118 logger.info('Started to build module dependency graph...'); 119 120 const depGraph = buildModuleDepGraph(scene); 121 122 const jsonRes = JSON.stringify(depGraph.toJson()); 123 FileUtils.writeToFile(moduleDepGraphJson, jsonRes, WriteFileMode.OVERWRITE); 124 logger.info('Building module graph in json format has completed.'); 125 126 const dotRes = depGraph.dump(); 127 FileUtils.writeToFile(moduleDepGraphDot, dotRes, WriteFileMode.OVERWRITE); 128 logger.info('Building module graph in dot format has completed.'); 129 130 logger.info('Building file module graph completed.'); 131} 132 133export enum Tools { 134 ImportChains = 0, 135 DepGraph = 1, 136}