1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.releaseparser; 18 19 import com.android.cts.releaseparser.ReleaseProto.*; 20 21 import java.io.File; 22 import java.io.FileWriter; 23 import java.io.IOException; 24 import java.io.PrintWriter; 25 import java.nio.charset.StandardCharsets; 26 import java.nio.file.Path; 27 import java.nio.file.Paths; 28 import java.security.MessageDigest; 29 import java.security.NoSuchAlgorithmException; 30 import java.util.ArrayList; 31 import java.util.Base64; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 37 class ReleaseParser { 38 private static final String ROOT_FOLDER_TAG = "/"; 39 // configuration option 40 private static final String NOT_SHARDABLE_TAG = "not-shardable"; 41 // test class option 42 private static final String RUNTIME_HIT_TAG = "runtime-hint"; 43 // com.android.tradefed.testtype.AndroidJUnitTest option 44 private static final String PACKAGE_TAG = "package"; 45 // com.android.compatibility.common.tradefed.testtype.JarHostTest option 46 private static final String JAR_NAME_TAG = "jar"; 47 // com.android.tradefed.testtype.GTest option 48 private static final String NATIVE_TEST_DEVICE_PATH_TAG = "native-test-device-path"; 49 private static final String MODULE_TAG = "module-name"; 50 51 private static final String SUITE_API_INSTALLER_TAG = 52 "com.android.tradefed.targetprep.suite.SuiteApkInstaller"; 53 private static final String JAR_HOST_TEST_TAG = 54 "com.android.compatibility.common.tradefed.testtype.JarHostTest"; 55 // com.android.tradefed.targetprep.suite.SuiteApkInstaller option 56 private static final String TEST_FILE_NAME_TAG = "test-file-name"; 57 // com.android.compatibility.common.tradefed.targetprep.FilePusher option 58 private static final String PUSH_TAG = "push"; 59 60 // test class 61 private static final String ANDROID_JUNIT_TEST_TAG = 62 "com.android.tradefed.testtype.AndroidJUnitTest"; 63 64 private static final String TESTCASES_FOLDER_FORMAT = "testcases/%s"; 65 66 private final String mFolderPath; 67 private Path mRootPath; 68 private ReleaseContent.Builder mRelContentBuilder; 69 private Map<String, Entry> mEntries; 70 ReleaseParser(String folder)71 ReleaseParser(String folder) { 72 mFolderPath = folder; 73 File fFile = new File(mFolderPath); 74 mRootPath = Paths.get(fFile.getAbsolutePath()); 75 mEntries = new HashMap<String, Entry>(); 76 } 77 getReleaseId()78 public String getReleaseId() { 79 ReleaseContent relContent = getReleaseContent(); 80 return getReleaseId(relContent); 81 } 82 getReleaseId(ReleaseContent relContent)83 public static String getReleaseId(ReleaseContent relContent) { 84 return String.format( 85 "%s-%s-%s", 86 relContent.getFullname(), relContent.getVersion(), relContent.getBuildNumber()); 87 } 88 getReleaseContent()89 public ReleaseContent getReleaseContent() { 90 if (mRelContentBuilder == null) { 91 mRelContentBuilder = ReleaseContent.newBuilder(); 92 // default APP_DISTRIBUTION_PACKAGE if no BUILD_PROP nor TEST_SUITE_TRADEFED is found 93 mRelContentBuilder.setReleaseType(ReleaseType.APP_DISTRIBUTION_PACKAGE); 94 // also add the root folder entry 95 Entry.Builder fBuilder = parseFolder(mFolderPath); 96 if (mRelContentBuilder.getName().equals("")) { 97 System.err.println("Release Name unknown!"); 98 mRelContentBuilder.setName(mFolderPath); 99 mRelContentBuilder.setFullname(mFolderPath); 100 } 101 fBuilder.setRelativePath(ROOT_FOLDER_TAG); 102 String relId = getReleaseId(mRelContentBuilder.build()); 103 fBuilder.setName(relId); 104 mRelContentBuilder.setReleaseId(relId); 105 mRelContentBuilder.setContentId(fBuilder.getContentId()); 106 mRelContentBuilder.setSize(fBuilder.getSize()); 107 Entry fEntry = fBuilder.build(); 108 mEntries.put(fEntry.getRelativePath(), fEntry); 109 mRelContentBuilder.putAllEntries(mEntries); 110 } 111 return mRelContentBuilder.build(); 112 } 113 114 // Parse all files in a folder and return the foler entry builder parseFolder(String fPath)115 private Entry.Builder parseFolder(String fPath) { 116 Entry.Builder folderEntry = Entry.newBuilder(); 117 File folder = new File(fPath); 118 Path folderPath = Paths.get(folder.getAbsolutePath()); 119 String folderRelativePath = mRootPath.relativize(folderPath).toString(); 120 File[] fileList = folder.listFiles(); 121 Long folderSize = 0L; 122 List<Entry> entryList = new ArrayList<Entry>(); 123 124 // walks through all files 125 System.out.println("Parsing: " + folderRelativePath); 126 // skip if it's a symbolic link to a folder 127 if (fileList != null) { 128 for (File file : fileList) { 129 if (file.isFile()) { 130 String fileRelativePath = 131 mRootPath.relativize(Paths.get(file.getAbsolutePath())).toString(); 132 FileParser fParser = FileParser.getParser(file); 133 Entry.Builder fileEntryBuilder = fParser.getFileEntryBuilder(); 134 fileEntryBuilder.setRelativePath(fileRelativePath); 135 136 if (folderRelativePath.isEmpty()) { 137 fileEntryBuilder.setParentFolder(ROOT_FOLDER_TAG); 138 } else { 139 fileEntryBuilder.setParentFolder(folderRelativePath); 140 } 141 142 Entry.EntryType eType = fParser.getType(); 143 switch (eType) { 144 case TEST_SUITE_TRADEFED: 145 mRelContentBuilder.setTestSuiteTradefed(fileRelativePath); 146 TestSuiteTradefedParser tstParser = (TestSuiteTradefedParser) fParser; 147 // get [cts]-known-failures.xml 148 mRelContentBuilder.addAllKnownFailures(tstParser.getKnownFailureList()); 149 mRelContentBuilder.setName(tstParser.getName()); 150 mRelContentBuilder.setFullname(tstParser.getFullName()); 151 mRelContentBuilder.setBuildNumber(tstParser.getBuildNumber()); 152 mRelContentBuilder.setTargetArch(tstParser.getTargetArch()); 153 mRelContentBuilder.setVersion(tstParser.getVersion()); 154 mRelContentBuilder.setReleaseType(ReleaseType.TEST_SUITE); 155 break; 156 case BUILD_PROP: 157 BuildPropParser bpParser = (BuildPropParser) fParser; 158 try { 159 mRelContentBuilder.setReleaseType(ReleaseType.DEVICE_BUILD); 160 mRelContentBuilder.setName(bpParser.getName()); 161 mRelContentBuilder.setFullname(bpParser.getFullName()); 162 mRelContentBuilder.setBuildNumber(bpParser.getBuildNumber()); 163 mRelContentBuilder.setVersion(bpParser.getVersion()); 164 mRelContentBuilder.putAllProperties(bpParser.getProperties()); 165 } catch (Exception e) { 166 System.err.println( 167 "No product name, version & etc. in " 168 + file.getAbsoluteFile() 169 + ", err:" 170 + e.getMessage()); 171 } 172 break; 173 default: 174 } 175 // System.err.println("File:" + file.getAbsoluteFile()); 176 if (fParser.getDependencies() != null) { 177 fileEntryBuilder.addAllDependencies(fParser.getDependencies()); 178 } 179 if (fParser.getDynamicLoadingDependencies() != null) { 180 fileEntryBuilder.addAllDynamicLoadingDependencies( 181 fParser.getDynamicLoadingDependencies()); 182 } 183 fileEntryBuilder.setAbiBits(fParser.getAbiBits()); 184 fileEntryBuilder.setAbiArchitecture(fParser.getAbiArchitecture()); 185 186 Entry fEntry = fileEntryBuilder.build(); 187 entryList.add(fEntry); 188 mEntries.put(fEntry.getRelativePath(), fEntry); 189 folderSize += file.length(); 190 } else if (file.isDirectory()) { 191 // Checks subfolders 192 Entry.Builder subFolderEntry = parseFolder(file.getAbsolutePath()); 193 if (folderRelativePath.isEmpty()) { 194 subFolderEntry.setParentFolder(ROOT_FOLDER_TAG); 195 } else { 196 subFolderEntry.setParentFolder(folderRelativePath); 197 } 198 Entry sfEntry = subFolderEntry.build(); 199 entryList.add(sfEntry); 200 mEntries.put(sfEntry.getRelativePath(), sfEntry); 201 folderSize += sfEntry.getSize(); 202 } 203 } 204 } 205 folderEntry.setName(folderRelativePath); 206 folderEntry.setSize(folderSize); 207 folderEntry.setType(Entry.EntryType.FOLDER); 208 folderEntry.setContentId(getFolderContentId(folderEntry, entryList)); 209 folderEntry.setRelativePath(folderRelativePath); 210 return folderEntry; 211 } 212 getFolderContentId(Entry.Builder folderEntry, List<Entry> entryList)213 private static String getFolderContentId(Entry.Builder folderEntry, List<Entry> entryList) { 214 String id = null; 215 try { 216 MessageDigest md = MessageDigest.getInstance("SHA-256"); 217 for (Entry entry : entryList) { 218 md.update(entry.getContentId().getBytes(StandardCharsets.UTF_8)); 219 } 220 // Converts to Base64 String 221 id = Base64.getEncoder().encodeToString(md.digest()); 222 } catch (NoSuchAlgorithmException e) { 223 System.err.println("NoSuchAlgorithmException:" + e.getMessage()); 224 } 225 return id; 226 } 227 228 // writes releaes content to a CSV file writeRelesaeContentCsvFile(String relNameVer, String csvFile)229 public void writeRelesaeContentCsvFile(String relNameVer, String csvFile) { 230 try { 231 FileWriter fWriter = new FileWriter(csvFile); 232 PrintWriter pWriter = new PrintWriter(fWriter); 233 // Header 234 pWriter.printf( 235 "release,type,name,size,relative_path,content_id,parent_folder,code_id,architecture,bits,dependencies,dynamic_loading_dependencies,services\n"); 236 for (Entry entry : getFileEntries()) { 237 pWriter.printf( 238 "%s,%s,%s,%d,%s,%s,%s,%s,%s,%d,%s,%s,%s\n", 239 relNameVer, 240 entry.getType(), 241 entry.getName(), 242 entry.getSize(), 243 entry.getRelativePath(), 244 entry.getContentId(), 245 entry.getParentFolder(), 246 entry.getCodeId(), 247 entry.getAbiArchitecture(), 248 entry.getAbiBits(), 249 String.join(" ", entry.getDependenciesList()), 250 String.join(" ", entry.getDynamicLoadingDependenciesList()), 251 RcParser.toString(entry.getServicesList())); 252 } 253 pWriter.flush(); 254 pWriter.close(); 255 } catch (IOException e) { 256 System.err.println("IOException:" + e.getMessage()); 257 } 258 } 259 260 // writes known failures to a CSV file writeKnownFailureCsvFile(String relNameVer, String csvFile)261 public void writeKnownFailureCsvFile(String relNameVer, String csvFile) { 262 ReleaseContent relContent = getReleaseContent(); 263 if (relContent.getKnownFailuresList().size() == 0) { 264 // Skip if no Known Failures 265 return; 266 } 267 268 try { 269 FileWriter fWriter = new FileWriter(csvFile); 270 PrintWriter pWriter = new PrintWriter(fWriter); 271 //Header 272 pWriter.printf("release,compatibility:exclude-filter\n"); 273 for (String kf : relContent.getKnownFailuresList()) { 274 pWriter.printf("%s,%s\n", relNameVer, kf); 275 } 276 pWriter.flush(); 277 pWriter.close(); 278 } catch (IOException e) { 279 System.err.println("IOException:" + e.getMessage()); 280 } 281 } 282 getFileEntries()283 public Collection<Entry> getFileEntries() { 284 return getReleaseContent().getEntries().values(); 285 } 286 } 287