xref: /aosp_15_r20/development/tools/idegen/src/Eclipse.java (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker 
17*90c8c64dSAndroid Build Coastguard Worker import java.io.File;
18*90c8c64dSAndroid Build Coastguard Worker import java.io.IOException;
19*90c8c64dSAndroid Build Coastguard Worker import java.util.SortedSet;
20*90c8c64dSAndroid Build Coastguard Worker import java.util.TreeMap;
21*90c8c64dSAndroid Build Coastguard Worker import java.util.TreeSet;
22*90c8c64dSAndroid Build Coastguard Worker import java.util.Collection;
23*90c8c64dSAndroid Build Coastguard Worker import java.util.ArrayList;
24*90c8c64dSAndroid Build Coastguard Worker import java.util.List;
25*90c8c64dSAndroid Build Coastguard Worker import java.util.regex.Pattern;
26*90c8c64dSAndroid Build Coastguard Worker 
27*90c8c64dSAndroid Build Coastguard Worker /**
28*90c8c64dSAndroid Build Coastguard Worker  * Generates an Eclipse project.
29*90c8c64dSAndroid Build Coastguard Worker  */
30*90c8c64dSAndroid Build Coastguard Worker public class Eclipse {
31*90c8c64dSAndroid Build Coastguard Worker 
32*90c8c64dSAndroid Build Coastguard Worker     /**
33*90c8c64dSAndroid Build Coastguard Worker      * Generates an Eclipse .classpath file from the given configuration.
34*90c8c64dSAndroid Build Coastguard Worker      */
generateFrom(Configuration c)35*90c8c64dSAndroid Build Coastguard Worker     public static void generateFrom(Configuration c) throws IOException {
36*90c8c64dSAndroid Build Coastguard Worker         StringBuilder classpath = new StringBuilder();
37*90c8c64dSAndroid Build Coastguard Worker 
38*90c8c64dSAndroid Build Coastguard Worker         classpath.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
39*90c8c64dSAndroid Build Coastguard Worker                 + "<classpath>\n");
40*90c8c64dSAndroid Build Coastguard Worker 
41*90c8c64dSAndroid Build Coastguard Worker         /*
42*90c8c64dSAndroid Build Coastguard Worker          * If the user has a file named "path-precedence" in their project's
43*90c8c64dSAndroid Build Coastguard Worker          * root directory, we'll order source roots based on how they match
44*90c8c64dSAndroid Build Coastguard Worker          * regular expressions in that file. Source roots that match earlier
45*90c8c64dSAndroid Build Coastguard Worker          * patterns will come sooner in configuration file.
46*90c8c64dSAndroid Build Coastguard Worker          */
47*90c8c64dSAndroid Build Coastguard Worker         List<Pattern> patterns = new ArrayList<Pattern>();
48*90c8c64dSAndroid Build Coastguard Worker 
49*90c8c64dSAndroid Build Coastguard Worker         File precedence = new File("path-precedence");
50*90c8c64dSAndroid Build Coastguard Worker         if (precedence.exists()) {
51*90c8c64dSAndroid Build Coastguard Worker             Configuration.parseFile(precedence, patterns);
52*90c8c64dSAndroid Build Coastguard Worker         } else {
53*90c8c64dSAndroid Build Coastguard Worker             // Put ./out at the bottom by default.
54*90c8c64dSAndroid Build Coastguard Worker             patterns.add(Pattern.compile("^(?!out/)"));
55*90c8c64dSAndroid Build Coastguard Worker         }
56*90c8c64dSAndroid Build Coastguard Worker 
57*90c8c64dSAndroid Build Coastguard Worker         // Everything not matched by the user's precedence spec.
58*90c8c64dSAndroid Build Coastguard Worker         patterns.add(Pattern.compile(".*"));
59*90c8c64dSAndroid Build Coastguard Worker 
60*90c8c64dSAndroid Build Coastguard Worker 
61*90c8c64dSAndroid Build Coastguard Worker         List<Bucket> buckets = new ArrayList<Bucket>(patterns.size());
62*90c8c64dSAndroid Build Coastguard Worker         for (Pattern pattern : patterns) {
63*90c8c64dSAndroid Build Coastguard Worker             buckets.add(new Bucket(pattern));
64*90c8c64dSAndroid Build Coastguard Worker         }
65*90c8c64dSAndroid Build Coastguard Worker 
66*90c8c64dSAndroid Build Coastguard Worker         // Put source roots in respective buckets.
67*90c8c64dSAndroid Build Coastguard Worker         OUTER: for (File sourceRoot : c.sourceRoots) {
68*90c8c64dSAndroid Build Coastguard Worker             // Trim preceding "./" from path.
69*90c8c64dSAndroid Build Coastguard Worker             String path = sourceRoot.getPath().substring(2);
70*90c8c64dSAndroid Build Coastguard Worker 
71*90c8c64dSAndroid Build Coastguard Worker             for (Bucket bucket : buckets) {
72*90c8c64dSAndroid Build Coastguard Worker                 if (bucket.matches(path)) {
73*90c8c64dSAndroid Build Coastguard Worker                     bucket.sourceRoots.add(sourceRoot);
74*90c8c64dSAndroid Build Coastguard Worker                     continue OUTER;
75*90c8c64dSAndroid Build Coastguard Worker                 }
76*90c8c64dSAndroid Build Coastguard Worker             }
77*90c8c64dSAndroid Build Coastguard Worker         }
78*90c8c64dSAndroid Build Coastguard Worker 
79*90c8c64dSAndroid Build Coastguard Worker         // Output source roots to configuration file.
80*90c8c64dSAndroid Build Coastguard Worker         for (Bucket bucket : buckets) {
81*90c8c64dSAndroid Build Coastguard Worker             for (File sourceRoot : bucket.sourceRoots) {
82*90c8c64dSAndroid Build Coastguard Worker                 classpath.append("  <classpathentry kind=\"src\"");
83*90c8c64dSAndroid Build Coastguard Worker                 CharSequence excluding = constructExcluding(sourceRoot, c);
84*90c8c64dSAndroid Build Coastguard Worker                 if (excluding.length() > 0) {
85*90c8c64dSAndroid Build Coastguard Worker                     classpath.append(" excluding=\"")
86*90c8c64dSAndroid Build Coastguard Worker                             .append(excluding).append("\"");
87*90c8c64dSAndroid Build Coastguard Worker                 }
88*90c8c64dSAndroid Build Coastguard Worker                 classpath.append(" path=\"")
89*90c8c64dSAndroid Build Coastguard Worker                         .append(trimmed(sourceRoot)).append("\"/>\n");
90*90c8c64dSAndroid Build Coastguard Worker             }
91*90c8c64dSAndroid Build Coastguard Worker 
92*90c8c64dSAndroid Build Coastguard Worker         }
93*90c8c64dSAndroid Build Coastguard Worker 
94*90c8c64dSAndroid Build Coastguard Worker         // Output .jar entries.
95*90c8c64dSAndroid Build Coastguard Worker         for (File jar : c.jarFiles) {
96*90c8c64dSAndroid Build Coastguard Worker             classpath.append("  <classpathentry kind=\"lib\" path=\"")
97*90c8c64dSAndroid Build Coastguard Worker                     .append(trimmed(jar)).append("\"/>\n");
98*90c8c64dSAndroid Build Coastguard Worker         }
99*90c8c64dSAndroid Build Coastguard Worker 
100*90c8c64dSAndroid Build Coastguard Worker         /*
101*90c8c64dSAndroid Build Coastguard Worker          * Output directory. Unfortunately, Eclipse forces us to put it
102*90c8c64dSAndroid Build Coastguard Worker          * somewhere under the project directory.
103*90c8c64dSAndroid Build Coastguard Worker          */
104*90c8c64dSAndroid Build Coastguard Worker         classpath.append("  <classpathentry kind=\"output\" path=\""
105*90c8c64dSAndroid Build Coastguard Worker                 + "out/eclipse\"/>\n");
106*90c8c64dSAndroid Build Coastguard Worker 
107*90c8c64dSAndroid Build Coastguard Worker         classpath.append("</classpath>\n");
108*90c8c64dSAndroid Build Coastguard Worker 
109*90c8c64dSAndroid Build Coastguard Worker         Files.toFile(classpath.toString(), new File(".classpath"));
110*90c8c64dSAndroid Build Coastguard Worker     }
111*90c8c64dSAndroid Build Coastguard Worker 
112*90c8c64dSAndroid Build Coastguard Worker 
113*90c8c64dSAndroid Build Coastguard Worker     /**
114*90c8c64dSAndroid Build Coastguard Worker      * Constructs the "excluding" argument for a given source root.
115*90c8c64dSAndroid Build Coastguard Worker      */
constructExcluding(File sourceRoot, Configuration c)116*90c8c64dSAndroid Build Coastguard Worker     private static CharSequence constructExcluding(File sourceRoot,
117*90c8c64dSAndroid Build Coastguard Worker             Configuration c) {
118*90c8c64dSAndroid Build Coastguard Worker         StringBuilder classpath = new StringBuilder();
119*90c8c64dSAndroid Build Coastguard Worker         String path = sourceRoot.getPath();
120*90c8c64dSAndroid Build Coastguard Worker 
121*90c8c64dSAndroid Build Coastguard Worker         // Exclude nested source roots.
122*90c8c64dSAndroid Build Coastguard Worker         SortedSet<File> nextRoots = c.sourceRoots.tailSet(sourceRoot);
123*90c8c64dSAndroid Build Coastguard Worker         int count = 0;
124*90c8c64dSAndroid Build Coastguard Worker         for (File nextRoot : nextRoots) {
125*90c8c64dSAndroid Build Coastguard Worker             // The first root is this root.
126*90c8c64dSAndroid Build Coastguard Worker             if (count == 0) {
127*90c8c64dSAndroid Build Coastguard Worker                 count++;
128*90c8c64dSAndroid Build Coastguard Worker                 continue;
129*90c8c64dSAndroid Build Coastguard Worker             }
130*90c8c64dSAndroid Build Coastguard Worker 
131*90c8c64dSAndroid Build Coastguard Worker             String nextPath = nextRoot.getPath();
132*90c8c64dSAndroid Build Coastguard Worker             if (!nextPath.startsWith(path)) {
133*90c8c64dSAndroid Build Coastguard Worker                 break;
134*90c8c64dSAndroid Build Coastguard Worker             }
135*90c8c64dSAndroid Build Coastguard Worker 
136*90c8c64dSAndroid Build Coastguard Worker             if (count > 1) {
137*90c8c64dSAndroid Build Coastguard Worker                 classpath.append('|');
138*90c8c64dSAndroid Build Coastguard Worker             }
139*90c8c64dSAndroid Build Coastguard Worker             classpath.append(nextPath.substring(path.length() + 1))
140*90c8c64dSAndroid Build Coastguard Worker                     .append('/');
141*90c8c64dSAndroid Build Coastguard Worker 
142*90c8c64dSAndroid Build Coastguard Worker             count++;
143*90c8c64dSAndroid Build Coastguard Worker         }
144*90c8c64dSAndroid Build Coastguard Worker 
145*90c8c64dSAndroid Build Coastguard Worker         // Exclude excluded directories under this source root.
146*90c8c64dSAndroid Build Coastguard Worker         SortedSet<File> excludedDirs = c.excludedDirs.tailSet(sourceRoot);
147*90c8c64dSAndroid Build Coastguard Worker         for (File excludedDir : excludedDirs) {
148*90c8c64dSAndroid Build Coastguard Worker             String excludedPath = excludedDir.getPath();
149*90c8c64dSAndroid Build Coastguard Worker             if (!excludedPath.startsWith(path)) {
150*90c8c64dSAndroid Build Coastguard Worker                 break;
151*90c8c64dSAndroid Build Coastguard Worker             }
152*90c8c64dSAndroid Build Coastguard Worker 
153*90c8c64dSAndroid Build Coastguard Worker             if (count > 1) {
154*90c8c64dSAndroid Build Coastguard Worker                 classpath.append('|');
155*90c8c64dSAndroid Build Coastguard Worker             }
156*90c8c64dSAndroid Build Coastguard Worker             classpath.append(excludedPath.substring(path.length() + 1))
157*90c8c64dSAndroid Build Coastguard Worker                     .append('/');
158*90c8c64dSAndroid Build Coastguard Worker 
159*90c8c64dSAndroid Build Coastguard Worker             count++;
160*90c8c64dSAndroid Build Coastguard Worker         }
161*90c8c64dSAndroid Build Coastguard Worker 
162*90c8c64dSAndroid Build Coastguard Worker         return classpath;
163*90c8c64dSAndroid Build Coastguard Worker     }
164*90c8c64dSAndroid Build Coastguard Worker 
165*90c8c64dSAndroid Build Coastguard Worker     /**
166*90c8c64dSAndroid Build Coastguard Worker      * Returns the trimmed path.
167*90c8c64dSAndroid Build Coastguard Worker      */
trimmed(File file)168*90c8c64dSAndroid Build Coastguard Worker     private static String trimmed(File file) {
169*90c8c64dSAndroid Build Coastguard Worker         return file.getPath().substring(2);
170*90c8c64dSAndroid Build Coastguard Worker     }
171*90c8c64dSAndroid Build Coastguard Worker 
172*90c8c64dSAndroid Build Coastguard Worker     /**
173*90c8c64dSAndroid Build Coastguard Worker      * A precedence bucket for source roots.
174*90c8c64dSAndroid Build Coastguard Worker      */
175*90c8c64dSAndroid Build Coastguard Worker     private static class Bucket {
176*90c8c64dSAndroid Build Coastguard Worker 
177*90c8c64dSAndroid Build Coastguard Worker         private final Pattern pattern;
178*90c8c64dSAndroid Build Coastguard Worker         private final List<File> sourceRoots = new ArrayList<File>();
179*90c8c64dSAndroid Build Coastguard Worker 
Bucket(Pattern pattern)180*90c8c64dSAndroid Build Coastguard Worker         private Bucket(Pattern pattern) {
181*90c8c64dSAndroid Build Coastguard Worker             this.pattern = pattern;
182*90c8c64dSAndroid Build Coastguard Worker         }
183*90c8c64dSAndroid Build Coastguard Worker 
matches(String path)184*90c8c64dSAndroid Build Coastguard Worker         private boolean matches(String path) {
185*90c8c64dSAndroid Build Coastguard Worker             return pattern.matcher(path).find();
186*90c8c64dSAndroid Build Coastguard Worker         }
187*90c8c64dSAndroid Build Coastguard Worker     }
188*90c8c64dSAndroid Build Coastguard Worker }
189