1 /* 2 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 package com.sk.utils; 16 17 import com.alibaba.fastjson2.JSON; 18 import com.alibaba.fastjson2.JSONObject; 19 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.intellij.notification.NotificationType; 21 import com.intellij.openapi.diagnostic.Logger; 22 import com.intellij.openapi.project.Project; 23 import org.apache.http.util.TextUtils; 24 25 import java.io.BufferedReader; 26 import java.io.File; 27 import java.io.FileInputStream; 28 import java.io.FileNotFoundException; 29 import java.io.FileWriter; 30 import java.io.IOException; 31 import java.io.InputStreamReader; 32 import java.nio.charset.StandardCharsets; 33 import java.util.Arrays; 34 import java.util.Properties; 35 import java.util.regex.Pattern; 36 37 /** 38 * 文本文件工具 39 * 40 * @author: xudong 41 * @see: file utils 42 * @version: v1.0.0 43 * @since 2022-02-21 44 */ 45 public class FileUtil { 46 private static final Logger LOG = Logger.getInstance(FileUtil.class); 47 48 private static final int COMPILE_SDK_VERSION = 5; 49 50 private static final String LF = getNewline(); // 换行符 51 52 private static final String BUILD_OPTION = "{" + LF 53 + " \"externalNativeOptions\": {" + LF 54 + " \"path\": \"\"," + LF 55 + " \"arguments\": \"\"," + LF 56 + " \"cppFlags\": \"\"," + LF 57 + " }" + LF 58 + " }"; 59 60 /** 61 * 改写build-profile.json5文件 62 * 63 * @param buildJsonFilePath build-profile.json5 文件路径 64 * @param cmakeFilePath CMakeList.txt 文件路径 65 */ writeBuildJsonFile(String buildJsonFilePath, String cmakeFilePath)66 public void writeBuildJsonFile(String buildJsonFilePath, String cmakeFilePath) { 67 try { 68 String buildStr = readWholeFile(buildJsonFilePath); 69 JSONObject buildObj = (JSONObject) JSON.parse(buildStr); 70 JSONObject buildOptionObj = (JSONObject) JSON.parse(BUILD_OPTION); 71 ((JSONObject) buildOptionObj.get("externalNativeOptions")).put("path", cmakeFilePath); 72 buildObj.put("buildOption", buildOptionObj); 73 ObjectMapper mapper = new ObjectMapper(); 74 buildStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(buildObj); 75 76 writeContentToFile(buildJsonFilePath, buildStr, false); 77 } catch (IOException ioException) { 78 LOG.error("Failed to write file [" + buildJsonFilePath + "], error: " + ioException); 79 } 80 } 81 82 /** 83 * 将数据写入到指定文件中 84 * 85 * @param path 文件路径 86 * @param content 数据内容 87 * @param isAppend 文件是否追加写入 88 */ writeContentToFile(String path, String content, boolean isAppend)89 public void writeContentToFile(String path, String content, boolean isAppend) { 90 File file = new File(path); 91 try (FileWriter fw = new FileWriter(file, isAppend)) { 92 fw.write(FileUtil.getNewline() + content + FileUtil.getNewline()); 93 } catch (IOException ioException) { 94 LOG.error("Failed to write file [" + path + "], error: " + ioException); 95 } 96 } 97 98 /** 99 * 创建文件 100 * 101 * @param path 文件路径 102 * @return 文件路径 103 */ makeFile(String path)104 public String makeFile(String path) { 105 File file = new File(path); 106 if (!file.exists()) { 107 try { 108 boolean isCreateFile = file.createNewFile(); 109 if (isCreateFile) { 110 LOG.info(String.format("makeFile %s success", path)); 111 } 112 } catch (IOException ioException) { 113 LOG.error(String.format("makeFile %s error:%s", path, ioException)); 114 return ""; 115 } 116 } 117 return file.getPath(); 118 } 119 120 /** 121 * 获得 pathA 相对于 pathB的相对路径 122 * 123 * @param pathA 路径A,如 D:\xx\yy\zz\a1\a2 124 * @param pathB 路径B, 如 D:\xx\yy\zz\b1\b2\b3 125 * @return pathA 相对于 pathB的相对路径: ../../../a1/a2/ 126 */ getRelativePath(String pathA, String pathB)127 public String getRelativePath(String pathA, String pathB) { 128 String separatorStr = File.separator.equals("\\") ? "\\\\" : File.separator; 129 String[] pathAList = pathA.split(separatorStr); 130 String[] pathBList = pathB.split(separatorStr); 131 132 int pos = 0; 133 for (; pos < pathAList.length && pos < pathBList.length; ++pos) { 134 if (!pathAList[pos].equals(pathBList[pos])) { 135 // 找到两个path路径存在差异的位置 136 break; 137 } 138 } 139 // 截取pathA和pathB路径字符串的差异部分 140 String[] diffPathAList = Arrays.copyOfRange(pathAList, pos, pathAList.length); 141 String[] diffPathBList = Arrays.copyOfRange(pathBList, pos, pathBList.length); 142 143 // pathA的差异字符串作为相对路径的结尾部分 144 String pathAStr = String.join("/", diffPathAList); 145 pathAStr = pathAStr.isBlank() ? "" : pathAStr + "/"; 146 147 // 根据pathB的差异目录层级生成向上跳转字符串 148 String rollbackPath = ""; 149 for (int i = 0; i < diffPathBList.length; ++i) { 150 rollbackPath += "../"; 151 } 152 rollbackPath = rollbackPath.isEmpty() ? "./" : rollbackPath; 153 154 // 相对路径 = 向上跳转部分 + pathA的差异部分 155 return rollbackPath + pathAStr; 156 } 157 158 /** 159 * 将错误信息输入到txt中 160 * 161 * @param path 路径 162 * @param content 内容 163 */ writeErrorToTxt(String path, String content)164 public void writeErrorToTxt(String path, String content) { 165 File file = new File(path); 166 try (FileWriter fw = new FileWriter(file, true)) { 167 fw.write(content + FileUtil.getNewline()); 168 } catch (IOException ioException) { 169 LOG.error("writeErrorToTxt io error" + ioException); 170 } 171 } 172 173 /** 174 * 判断文件是否包含指定字符串 175 * 176 * @param path 文件路径 177 * @param content 指定内容 178 * @return 是否包含指定字符串 179 * @throws IOException 异常信息 180 */ findStringInFile(String path, String content)181 public boolean findStringInFile(String path, String content) throws IOException { 182 File file = new File(path); 183 String[] command = content.split(FileUtil.getNewline()); 184 185 try (InputStreamReader read = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); 186 BufferedReader bufferedReader = new BufferedReader(read)) { 187 return isContainString(bufferedReader, command[1]); 188 } catch (FileNotFoundException foundException) { 189 LOG.error("file not found" + foundException); 190 return false; 191 } 192 } 193 isContainString(BufferedReader bufferedReader, String command)194 private boolean isContainString(BufferedReader bufferedReader, String command) { 195 String line = null; 196 while (true) { 197 try { 198 if ((line = bufferedReader.readLine()) == null) { 199 return false; 200 } 201 } catch (IOException ioException) { 202 LOG.error("findStringInFile IOException" + ioException); 203 } 204 205 if (line.contains(command)) { 206 return true; 207 } 208 } 209 } 210 211 /** 212 * 获取换行符 213 * 214 * @return 换行符 215 */ getNewline()216 public static String getNewline() { 217 return System.getProperty("line.separator"); 218 } 219 220 /** 221 * 正则匹配所选文件名是否符合规范 222 * 223 * @param fileName 文件名 224 * @return boolean 是否匹配 225 */ patternFileName(String fileName)226 public static boolean patternFileName(String fileName) { 227 String pattern = "((@ohos\\.)*([.a-z_A-Z0-9]+).d.ts)"; 228 return Pattern.matches(pattern, fileName); 229 } 230 231 /** 232 * check project SDK 233 * 234 * @param project projectid 235 * @param baseFile project root file 236 * @return boolean 237 */ checkProjectSDK(Project project, String baseFile)238 public static boolean checkProjectSDK(Project project, String baseFile) { 239 240 String gradlePath = ""; 241 File baseDir = new File(baseFile); 242 if (baseDir.isDirectory()) { 243 File[] childFile = baseDir.listFiles(); 244 assert childFile != null; 245 for (File file : childFile) { 246 if (file.getName().equals("build.gradle") || file.getName().equals("build-profile.json5")) { 247 gradlePath = file.getPath(); 248 } 249 } 250 } 251 252 Properties properties = new Properties(); 253 if (TextUtils.isBlank(gradlePath)) { 254 GenNotification.notifyMessage(project, "项目结构中没有grandle配置文件。", 255 "当前项目结构不支持", 256 NotificationType.WARNING); 257 return true; 258 } 259 try { 260 properties.load(new FileInputStream(gradlePath)); 261 } catch (IOException e) { 262 GenNotification.notifyMessage(project, e.getMessage(), "提示", NotificationType.ERROR); 263 LOG.error(String.format("Can not load file :%s . %s", gradlePath, e)); 264 return true; 265 } 266 String ohosSDK = properties.getProperty("compileSdkVersion"); 267 268 if (ohosSDK != null && Integer.parseInt(ohosSDK) < COMPILE_SDK_VERSION) { 269 GenNotification.notifyMessage(project, "SKD版本过低,NAPI仅支持5.0及以上版本", 270 "提示", 271 NotificationType.WARNING); 272 return true; 273 } 274 return false; 275 } 276 readWholeFile(String fileName)277 private String readWholeFile(String fileName) { 278 File file = new File(fileName); 279 byte[] rdBuf = new byte[(int) file.length()]; 280 try(FileInputStream in = new FileInputStream(file)) { 281 in.read(rdBuf); 282 return new String(rdBuf, "UTF-8"); 283 } catch (FileNotFoundException foundException) { 284 LOG.error(String.format("File %s does not exist.", fileName)); 285 } catch (IOException ioException) { 286 LOG.error(String.format("Failed to read file %s. Error: %s", fileName, ioException)); 287 } 288 return ""; 289 } 290 } 291