src/share/classes/com/sun/tools/sjavac/Source.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
1 /*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.sjavac;
27
28 import java.io.File;
29 import java.util.Set;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.ArrayList;
33 import java.util.Map;
34
35 /** A Source object maintains information about a source file.
36 * For example which package it belongs to and kind of source it is.
37 * The class also knows how to find source files (scanRoot) given include/exclude
38 * patterns and a root.
39 *
40 * <p><b>This is NOT part of any supported API.
41 * If you write code that depends on this, you do so at your own
42 * risk. This code and its internal interfaces are subject to change
43 * or deletion without notice.</b></p>
44 */
45 public class Source implements Comparable<Source> {
46 // The package the source belongs to.
47 private Package pkg;
48 // Name of this source file, relative its source root.
49 // For example: java/lang/Object.java
50 // Or if the source file is inside a module:
51 // jdk.base/java/lang/Object.java
52 private String name;
53 // What kind of file is this.
54 private String suffix;
55 // When this source file was last_modified
56 private long lastModified;
57 // The source File.
58 private File file;
59 // The source root under which file resides.
60 private File root;
61 // If the source is generated.
62 private boolean isGenerated;
63 // If the source is only linked to, not compiled.
64 private boolean linkedOnly;
65
66 @Override
67 public boolean equals(Object o) {
68 return (o instanceof Source) && name.equals(((Source)o).name);
69 }
70
71 @Override
72 public int compareTo(Source o) {
73 return name.compareTo(o.name);
74 }
75
76 @Override
77 public int hashCode() {
78 return name.hashCode();
79 }
80
81 public Source(Module m, String n, File f, File r) {
82 name = n;
83 int dp = n.lastIndexOf(".");
84 if (dp != -1) {
85 suffix = n.substring(dp);
86 } else {
87 suffix = "";
88 }
89 file = f;
90 root = r;
91 lastModified = f.lastModified();
92 linkedOnly = false;
93 }
94
95 public Source(Package p, String n, long lm) {
96 pkg = p;
97 name = n;
98 int dp = n.lastIndexOf(".");
99 if (dp != -1) {
100 suffix = n.substring(dp);
101 } else {
102 suffix = "";
103 }
104 file = null;
105 root = null;
106 lastModified = lm;
107 linkedOnly = false;
108 int ls = n.lastIndexOf('/');
109 }
110
111 public String name() { return name; }
112 public String suffix() { return suffix; }
113 public Package pkg() { return pkg; }
114 public File file() { return file; }
115 public File root() { return root; }
116 public long lastModified() {
117 return lastModified;
118 }
119
120 public void setPackage(Package p) {
121 pkg = p;
122 }
123
124 public void markAsGenerated() {
125 isGenerated = true;
126 }
127
128 public boolean isGenerated() {
129 return isGenerated;
130 }
131
132 public void markAsLinkedOnly() {
133 linkedOnly = true;
134 }
135
136 public boolean isLinkedOnly() {
137 return linkedOnly;
138 }
139
140 private void save(StringBuilder b) {
141 String CL = linkedOnly?"L":"C";
142 String GS = isGenerated?"G":"S";
143 b.append(GS+" "+CL+" "+name+" "+file.lastModified()+"\n");
144 }
145 // Parse a line that looks like this:
146 // S C /code/alfa/A.java 1357631228000
147 static public Source load(Package lastPackage, String l, boolean isGenerated) {
148 int sp = l.indexOf(' ',4);
149 if (sp == -1) return null;
150 String name = l.substring(4,sp);
151 long last_modified = Long.parseLong(l.substring(sp+1));
152
153 boolean isLinkedOnly = false;
154 if (l.charAt(2) == 'L') {
155 isLinkedOnly = true;
156 } else if (l.charAt(2) == 'C') {
157 isLinkedOnly = false;
158 } else return null;
159
160 Source s = new Source(lastPackage, name, last_modified);
161 s.file = new File(name);
162 if (isGenerated) s.markAsGenerated();
163 if (isLinkedOnly) s.markAsLinkedOnly();
164 return s;
165 }
166
167 public static void saveSources(Map<String,Source> sources, StringBuilder b) {
168 List<String> sorted_sources = new ArrayList<String>();
169 for (String key : sources.keySet()) {
170 sorted_sources.add(key);
171 }
172 Collections.sort(sorted_sources);
173 for (String key : sorted_sources) {
174 Source s = sources.get(key);
175 s.save(b);
176 }
177 }
178
179 /**
180 * Recurse into the directory root and find all files matchine the excl/incl/exclfiles/inclfiles rules.
181 * Detects the existence of module-info.java files and presumes that the directory it resides in
182 * is the name of the current module.
183 */
184 static public void scanRoot(File root,
185 Set<String> suffixes,
186 List<String> excludes, List<String> includes,
187 List<String> excludeFiles, List<String> includeFiles,
188 Map<String,Source> foundFiles,
189 Map<String,Module> foundModules,
190 Module currentModule,
191 boolean permitSourcesWithoutPackage,
192 boolean inGensrc,
193 boolean inLinksrc)
194 throws ProblemException {
195
196 if (root == null) return;
197 int root_prefix = root.getPath().length()+1;
198 // This is the root source directory, it must not contain any Java sources files
199 // because we do not allow Java source files without a package.
200 // (Unless of course --permit-sources-without-package has been specified.)
201 // It might contain other source files however, (for -tr and -copy) these will
202 // always be included, since no package pattern can match the root directory.
203 currentModule = addFilesInDir(root, root_prefix, root, suffixes, permitSourcesWithoutPackage,
204 excludeFiles, includeFiles, false,
205 foundFiles, foundModules, currentModule,
206 inGensrc, inLinksrc);
207
208 File[] dirfiles = root.listFiles();
209 for (File d : dirfiles) {
210 if (d.isDirectory()) {
211 // Descend into the directory structure.
212 scanDirectory(d, root_prefix, root, suffixes,
213 excludes, includes, excludeFiles, includeFiles,
214 false, foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
215 }
216 }
217 }
218
219 /**
220 * Test if a path matches any of the patterns given.
221 * The pattern foo.bar matches only foo.bar
222 * The pattern foo.* matches foo.bar and foo.bar.zoo etc
223 */
224 static private boolean hasMatch(String path, List<String> patterns) {
225 for (String p : patterns) {
226 // Exact match
227 if (p.equals(path)) {
228 return true;
229 }
230 // Single dot the end matches this package and all its subpackages.
231 if (p.endsWith(".*")) {
232 // Remove the wildcard
233 String patprefix = p.substring(0,p.length()-2);
234 // Does the path start with the pattern prefix?
235 if (path.startsWith(patprefix)) {
236 // If the path has the same length as the pattern prefix, then it is a match.
237 // If the path is longer, then make sure that
238 // the next part of the path starts with a dot (.) to prevent
239 // wildcard matching in the middle of a package name.
240 if (path.length()==patprefix.length() || path.charAt(patprefix.length())=='.') {
241 return true;
242 }
243 }
244 }
245 }
246 return false;
247 }
248
249 /**
250 * Matches patterns with the asterisk first. */
251 // The pattern foo/bar.java only matches foo/bar.java
252 // The pattern */bar.java matches foo/bar.java and zoo/bar.java etc
253 static private boolean hasFileMatch(String path, List<String> patterns) {
254 path = Util.normalizeDriveLetter(path);
255 for (String p : patterns) {
256 // Exact match
257 if (p.equals(path)) {
258 return true;
259 }
260 // Single dot the end matches this package and all its subpackages.
261 if (p.startsWith("*")) {
262 // Remove the wildcard
263 String patsuffix = p.substring(1);
264 // Does the path start with the pattern prefix?
265 if (path.endsWith(patsuffix)) {
266 return true;
267 }
268 }
269 }
270 return false;
271 }
272
273 /**
274 * Add the files in the directory, assuming that the file has not been excluded.
275 * Returns a fresh Module object, if this was a dir with a module-info.java file.
276 */
277 static private Module addFilesInDir(File dir, int rootPrefix, File root,
278 Set<String> suffixes, boolean allow_javas,
279 List<String> excludeFiles, List<String> includeFiles, boolean all,
280 Map<String,Source> foundFiles,
281 Map<String,Module> foundModules,
282 Module currentModule,
283 boolean inGensrc,
284 boolean inLinksrc)
285 throws ProblemException
286 {
287 for (File f : dir.listFiles()) {
288 if (f.isFile()) {
289 boolean should_add =
290 (excludeFiles == null || excludeFiles.isEmpty() || !hasFileMatch(f.getPath(), excludeFiles))
291 && (includeFiles == null || includeFiles.isEmpty() || hasFileMatch(f.getPath(), includeFiles));
292
293 if (should_add) {
294 if (!allow_javas && f.getName().endsWith(".java")) {
295 throw new ProblemException("No .java files are allowed in the source root "+dir.getPath()+
296 ", please remove "+f.getName());
297 }
298 // Extract the file name relative the root.
299 String fn = f.getPath().substring(rootPrefix);
300 // Extract the package name.
301 int sp = fn.lastIndexOf(File.separatorChar);
302 String pkg = "";
303 if (sp != -1) {
304 pkg = fn.substring(0,sp).replace(File.separatorChar,'.');
305 }
306 // Is this a module-info.java file?
307 if (fn.endsWith("module-info.java")) {
308 // Aha! We have recursed into a module!
309 if (!currentModule.name().equals("")) {
310 throw new ProblemException("You have an extra module-info.java inside a module! Please remove "+fn);
311 }
312 String module_name = fn.substring(0,fn.length()-16);
313 currentModule = new Module(module_name, f.getPath());
314 foundModules.put(module_name, currentModule);
315 }
316 // Extract the suffix.
317 int dp = fn.lastIndexOf(".");
318 String suffix = "";
319 if (dp > 0) {
320 suffix = fn.substring(dp);
321 }
322 // Should the file be added?
323 if (all || suffixes.contains(suffix)) {
324 Source of = foundFiles.get(f.getPath());
325 if (of != null) {
326 throw new ProblemException("You have already added the file "+fn+" from "+of.file().getPath());
327 }
328 of = currentModule.lookupSource(f.getPath());
329 if (of != null) {
330 // Oups, the source is already added, could be ok, could be not, lets check.
331 if (inLinksrc) {
332 // So we are collecting sources for linking only.
333 if (of.isLinkedOnly()) {
334 // Ouch, this one is also for linking only. Bad.
335 throw new ProblemException("You have already added the link only file "+fn+" from "+of.file().getPath());
336 }
337 // Ok, the existing source is to be compiled. Thus this link only is redundant
338 // since all compiled are also linked to. Continue to the next source.
339 // But we need to add the source, so that it will be visible to linking,
340 // if not the multi core compile will fail because a JavaCompiler cannot
341 // find the necessary dependencies for its part of the source.
342 foundFiles.put(f.getPath(), of);
343 continue;
344 } else {
345 // We are looking for sources to compile, if we find an existing to be compiled
346 // source with the same name, it is an internal error, since we must
347 // find the sources to be compiled before we find the sources to be linked to.
348 throw new ProblemException("Internal error: Double add of file "+fn+" from "+of.file().getPath());
349 }
350 }
351 Source s = new Source(currentModule, f.getPath(), f, root);
352 if (inGensrc) s.markAsGenerated();
353 if (inLinksrc) {
354 s.markAsLinkedOnly();
355 }
356 pkg = currentModule.name()+":"+pkg;
357 foundFiles.put(f.getPath(), s);
358 currentModule.addSource(pkg, s);
359 }
360 }
361 }
362 }
363 return currentModule;
364 }
365
366 private static boolean gurka = false;
367
368 static private void scanDirectory(File dir, int rootPrefix, File root,
369 Set<String> suffixes,
370 List<String> excludes, List<String> includes,
371 List<String> excludeFiles, List<String> includeFiles, boolean all,
372 Map<String,Source> foundFiles,
373 Map<String,Module> foundModules,
374 Module currentModule, boolean inGensrc, boolean inLinksrc)
375 throws ProblemException {
376
377 String pkg_name = "";
378 // Remove the root prefix from the dir path, and replace file separator with dots
379 // to get the package name.
380 if (dir.getPath().length() > rootPrefix) {
381 pkg_name = dir.getPath().substring(rootPrefix).replace(File.separatorChar,'.');
382 }
383 // Should this package directory be included and not excluded?
384 if (all || ((includes==null || includes.isEmpty() || hasMatch(pkg_name, includes)) &&
385 (excludes==null || excludes.isEmpty() || !hasMatch(pkg_name, excludes)))) {
386 // Add the source files.
387 currentModule = addFilesInDir(dir, rootPrefix, root, suffixes, true, excludeFiles, includeFiles, all,
388 foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
389 }
390
391 for (File d : dir.listFiles()) {
392 if (d.isDirectory()) {
393 // Descend into the directory structure.
394 scanDirectory(d, rootPrefix, root, suffixes,
395 excludes, includes, excludeFiles, includeFiles, all,
396 foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
397 }
398 }
399 }
400 }

mercurial