• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 package com.android.dependencymapper;
17 
18 import static com.android.dependencymapper.Utils.listClassesInJar;
19 
20 import com.android.dependencymapper.DependencyProto;
21 
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.util.List;
26 import java.util.Set;
27 
28 public class Main {
29 
main(String[] args)30     public static void main(String[] args) throws IOException, InterruptedException {
31         try {
32             InputData input = parseAndValidateInput(args);
33             generateDependencyMap(input);
34         } catch (IllegalArgumentException e) {
35             System.err.println("Error: " + e.getMessage());
36             showUsage();
37         }
38     }
39 
40     private static class InputData {
41         public Path srcList;
42         public Path classesJar;
43         public Path dependencyMapProto;
44 
InputData(Path srcList, Path classesJar, Path dependencyMapProto)45         public InputData(Path srcList, Path classesJar, Path dependencyMapProto) {
46             this.srcList = srcList;
47             this.classesJar = classesJar;
48             this.dependencyMapProto = dependencyMapProto;
49         }
50     }
51 
parseAndValidateInput(String[] args)52     private static InputData parseAndValidateInput(String[] args) {
53         for (String arg : args) {
54             if ("--help".equals(arg)) {
55                 showUsage();
56                 System.exit(0); // Indicate successful exit after showing help
57             }
58         }
59 
60         if (args.length != 6) { // Explicitly check for the correct number of arguments
61             throw new IllegalArgumentException("Incorrect number of arguments");
62         }
63 
64         Path srcList = null;
65         Path classesJar = null;
66         Path dependencyMapProto = null;
67 
68         for (int i = 0; i < args.length; i += 2) {
69             String arg = args[i].trim();
70             String argValue = args[i + 1].trim();
71 
72             switch (arg) {
73                 case "--src-path" -> srcList = Path.of(argValue);
74                 case "--jar-path" -> classesJar = Path.of(argValue);
75                 case "--dependency-map-path" -> dependencyMapProto = Path.of(argValue);
76                 default -> throw new IllegalArgumentException("Unknown argument: " + arg);
77             }
78         }
79 
80         // Validate file existence and readability
81         validateFile(srcList, "--src-path");
82         validateFile(classesJar, "--jar-path");
83 
84         return new InputData(srcList, classesJar, dependencyMapProto);
85     }
86 
validateFile(Path path, String argName)87     private static void validateFile(Path path, String argName) {
88         if (path == null) {
89             throw new IllegalArgumentException(argName + " is required");
90         }
91         if (!Files.exists(path)) {
92             throw new IllegalArgumentException(argName + " does not exist: " + path);
93         }
94         if (!Files.isReadable(path)) {
95             throw new IllegalArgumentException(argName + " is not readable: " + path);
96         }
97     }
98 
generateDependencyMap(InputData input)99     private static void generateDependencyMap(InputData input) {
100         // First collect all classes in the jar.
101         Set<String> classesInJar = listClassesInJar(input.classesJar);
102         // Perform dependency analysis.
103         List<ClassDependencyData> classDependencyDataList = ClassDependencyAnalyzer
104                 .analyze(input.classesJar, new ClassRelevancyFilter(classesInJar));
105         // Perform java source analysis.
106         List<JavaSourceData> javaSourceDataList = JavaSourceAnalyzer.analyze(input.srcList);
107         // Collect all dependencies and map them as DependencyProto.FileDependencyList
108         DependencyMapper dp = new DependencyMapper(classDependencyDataList, javaSourceDataList);
109         DependencyProto.FileDependencyList dependencyList =  dp.buildDependencyMaps();
110 
111         // Write the proto to output file
112         Utils.writeContentsToProto(dependencyList, input.dependencyMapProto);
113     }
114 
showUsage()115     private static void showUsage() {
116         System.err.println(
117                 "Usage: dependency-mapper "
118                         + "--src-path [src-list.rsp] "
119                         + "--jar-path [classes.jar] "
120                         + "--dependency-map-path [dependency-map.proto]");
121     }
122 
123 }