blob: 131c931098c5a59b846aefc6e6dfb790cdfc7cb2 [file] [log] [blame]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dependencymapper;
import static com.android.dependencymapper.Utils.listClassesInJar;
import com.android.dependencymapper.DependencyProto;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
try {
InputData input = parseAndValidateInput(args);
generateDependencyMap(input);
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage());
showUsage();
}
}
private static class InputData {
public Path srcList;
public Path classesJar;
public Path dependencyMapProto;
public InputData(Path srcList, Path classesJar, Path dependencyMapProto) {
this.srcList = srcList;
this.classesJar = classesJar;
this.dependencyMapProto = dependencyMapProto;
}
}
private static InputData parseAndValidateInput(String[] args) {
for (String arg : args) {
if ("--help".equals(arg)) {
showUsage();
System.exit(0); // Indicate successful exit after showing help
}
}
if (args.length != 6) { // Explicitly check for the correct number of arguments
throw new IllegalArgumentException("Incorrect number of arguments");
}
Path srcList = null;
Path classesJar = null;
Path dependencyMapProto = null;
for (int i = 0; i < args.length; i += 2) {
String arg = args[i].trim();
String argValue = args[i + 1].trim();
switch (arg) {
case "--src-path" -> srcList = Path.of(argValue);
case "--jar-path" -> classesJar = Path.of(argValue);
case "--dependency-map-path" -> dependencyMapProto = Path.of(argValue);
default -> throw new IllegalArgumentException("Unknown argument: " + arg);
}
}
// Validate file existence and readability
validateFile(srcList, "--src-path");
validateFile(classesJar, "--jar-path");
return new InputData(srcList, classesJar, dependencyMapProto);
}
private static void validateFile(Path path, String argName) {
if (path == null) {
throw new IllegalArgumentException(argName + " is required");
}
if (!Files.exists(path)) {
throw new IllegalArgumentException(argName + " does not exist: " + path);
}
if (!Files.isReadable(path)) {
throw new IllegalArgumentException(argName + " is not readable: " + path);
}
}
private static void generateDependencyMap(InputData input) {
// First collect all classes in the jar.
Set<String> classesInJar = listClassesInJar(input.classesJar);
// Perform dependency analysis.
List<ClassDependencyData> classDependencyDataList = ClassDependencyAnalyzer
.analyze(input.classesJar, new ClassRelevancyFilter(classesInJar));
// Perform java source analysis.
List<JavaSourceData> javaSourceDataList = JavaSourceAnalyzer.analyze(input.srcList);
// Collect all dependencies and map them as DependencyProto.FileDependencyList
DependencyMapper dp = new DependencyMapper(classDependencyDataList, javaSourceDataList);
DependencyProto.FileDependencyList dependencyList = dp.buildDependencyMaps();
// Write the proto to output file
Utils.writeContentsToProto(dependencyList, input.dependencyMapProto);
}
private static void showUsage() {
System.err.println(
"Usage: dependency-mapper "
+ "--src-path [src-list.rsp] "
+ "--jar-path [classes.jar] "
+ "--dependency-map-path [dependency-map.proto]");
}
}