66 |
66 |
67 import javax.lang.model.SourceVersion; |
67 import javax.lang.model.SourceVersion; |
68 import javax.tools.JavaFileManager; |
68 import javax.tools.JavaFileManager; |
69 import javax.tools.JavaFileManager.Location; |
69 import javax.tools.JavaFileManager.Location; |
70 import javax.tools.StandardJavaFileManager; |
70 import javax.tools.StandardJavaFileManager; |
|
71 import javax.tools.StandardJavaFileManager.PathFactory; |
71 import javax.tools.StandardLocation; |
72 import javax.tools.StandardLocation; |
72 |
73 |
73 import com.sun.tools.javac.code.Lint; |
74 import com.sun.tools.javac.code.Lint; |
74 import com.sun.tools.javac.main.Option; |
75 import com.sun.tools.javac.main.Option; |
75 import com.sun.tools.javac.resources.CompilerProperties.Errors; |
76 import com.sun.tools.javac.resources.CompilerProperties.Errors; |
119 */ |
120 */ |
120 private boolean warn; |
121 private boolean warn; |
121 |
122 |
122 private ModuleNameReader moduleNameReader; |
123 private ModuleNameReader moduleNameReader; |
123 |
124 |
124 static final Path javaHome = Paths.get(System.getProperty("java.home")); |
125 private PathFactory pathFactory = Paths::get; |
|
126 |
|
127 static final Path javaHome = FileSystems.getDefault().getPath(System.getProperty("java.home")); |
125 static final Path thisSystemModules = javaHome.resolve("lib").resolve("modules"); |
128 static final Path thisSystemModules = javaHome.resolve("lib").resolve("modules"); |
126 |
129 |
127 Map<Path, FileSystem> fileSystems = new LinkedHashMap<>(); |
130 Map<Path, FileSystem> fileSystems = new LinkedHashMap<>(); |
128 List<Closeable> closeables = new ArrayList<>(); |
131 List<Closeable> closeables = new ArrayList<>(); |
129 |
132 |
130 Locations() { |
133 Locations() { |
131 initHandlers(); |
134 initHandlers(); |
|
135 } |
|
136 |
|
137 Path getPath(String first, String... more) { |
|
138 return pathFactory.getPath(first, more); |
132 } |
139 } |
133 |
140 |
134 public void close() throws IOException { |
141 public void close() throws IOException { |
135 ListBuffer<IOException> list = new ListBuffer<>(); |
142 ListBuffer<IOException> list = new ListBuffer<>(); |
136 closeables.forEach(closeable -> { |
143 closeables.forEach(closeable -> { |
153 this.log = log; |
160 this.log = log; |
154 warn = lint.isEnabled(Lint.LintCategory.PATH); |
161 warn = lint.isEnabled(Lint.LintCategory.PATH); |
155 this.fsInfo = fsInfo; |
162 this.fsInfo = fsInfo; |
156 } |
163 } |
157 |
164 |
|
165 void setPathFactory(PathFactory f) { |
|
166 pathFactory = f; |
|
167 } |
|
168 |
158 boolean isDefaultBootClassPath() { |
169 boolean isDefaultBootClassPath() { |
159 BootClassPathLocationHandler h |
170 BootClassPathLocationHandler h |
160 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); |
171 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); |
161 return h.isDefault(); |
172 return h.isDefault(); |
162 } |
173 } |
165 * Split a search path into its elements. Empty path elements will be ignored. |
176 * Split a search path into its elements. Empty path elements will be ignored. |
166 * |
177 * |
167 * @param searchPath The search path to be split |
178 * @param searchPath The search path to be split |
168 * @return The elements of the path |
179 * @return The elements of the path |
169 */ |
180 */ |
170 private static Iterable<Path> getPathEntries(String searchPath) { |
181 private Iterable<Path> getPathEntries(String searchPath) { |
171 return getPathEntries(searchPath, null); |
182 return getPathEntries(searchPath, null); |
172 } |
183 } |
173 |
184 |
174 /** |
185 /** |
175 * Split a search path into its elements. If emptyPathDefault is not null, all empty elements in the |
186 * Split a search path into its elements. If emptyPathDefault is not null, all empty elements in the |
179 * @param searchPath The search path to be split |
190 * @param searchPath The search path to be split |
180 * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore |
191 * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore |
181 * empty path elements |
192 * empty path elements |
182 * @return The elements of the path |
193 * @return The elements of the path |
183 */ |
194 */ |
184 private static Iterable<Path> getPathEntries(String searchPath, Path emptyPathDefault) { |
195 private Iterable<Path> getPathEntries(String searchPath, Path emptyPathDefault) { |
185 ListBuffer<Path> entries = new ListBuffer<>(); |
196 ListBuffer<Path> entries = new ListBuffer<>(); |
186 for (String s: searchPath.split(Pattern.quote(File.pathSeparator), -1)) { |
197 for (String s: searchPath.split(Pattern.quote(File.pathSeparator), -1)) { |
187 if (s.isEmpty()) { |
198 if (s.isEmpty()) { |
188 if (emptyPathDefault != null) { |
199 if (emptyPathDefault != null) { |
189 entries.add(emptyPathDefault); |
200 entries.add(emptyPathDefault); |
190 } |
201 } |
191 } else { |
202 } else { |
192 entries.add(Paths.get(s)); |
203 entries.add(getPath(s)); |
193 } |
204 } |
194 } |
205 } |
195 return entries; |
206 return entries; |
196 } |
207 } |
197 |
208 |
463 |
474 |
464 // TODO: could/should validate outputDir exists and is a directory |
475 // TODO: could/should validate outputDir exists and is a directory |
465 // need to decide how best to report issue for benefit of |
476 // need to decide how best to report issue for benefit of |
466 // direct API call on JavaFileManager.handleOption(specifies IAE) |
477 // direct API call on JavaFileManager.handleOption(specifies IAE) |
467 // vs. command line decoding. |
478 // vs. command line decoding. |
468 outputDir = (value == null) ? null : Paths.get(value); |
479 outputDir = (value == null) ? null : getPath(value); |
469 return true; |
480 return true; |
470 } |
481 } |
471 |
482 |
472 @Override |
483 @Override |
473 Collection<Path> getPaths() { |
484 Collection<Path> getPaths() { |
604 |
615 |
605 @Override |
616 @Override |
606 protected SearchPath createPath() { |
617 protected SearchPath createPath() { |
607 return new SearchPath() |
618 return new SearchPath() |
608 .expandJarClassPaths(true) // Only search user jars for Class-Paths |
619 .expandJarClassPaths(true) // Only search user jars for Class-Paths |
609 .emptyPathDefault(Paths.get(".")); // Empty path elt ==> current directory |
620 .emptyPathDefault(getPath(".")); // Empty path elt ==> current directory |
610 } |
621 } |
611 |
622 |
612 private void lazy() { |
623 private void lazy() { |
613 if (searchPath == null) { |
624 if (searchPath == null) { |
614 setPaths(null); |
625 setPaths(null); |
1168 Map<String, Collection<Path>> map = new LinkedHashMap<>(); |
1179 Map<String, Collection<Path>> map = new LinkedHashMap<>(); |
1169 final String MARKER = "*"; |
1180 final String MARKER = "*"; |
1170 for (String seg: segments) { |
1181 for (String seg: segments) { |
1171 int markStart = seg.indexOf(MARKER); |
1182 int markStart = seg.indexOf(MARKER); |
1172 if (markStart == -1) { |
1183 if (markStart == -1) { |
1173 add(map, Paths.get(seg), null); |
1184 add(map, getPath(seg), null); |
1174 } else { |
1185 } else { |
1175 if (markStart == 0 || !isSeparator(seg.charAt(markStart - 1))) { |
1186 if (markStart == 0 || !isSeparator(seg.charAt(markStart - 1))) { |
1176 throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg); |
1187 throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg); |
1177 } |
1188 } |
1178 Path prefix = Paths.get(seg.substring(0, markStart - 1)); |
1189 Path prefix = getPath(seg.substring(0, markStart - 1)); |
1179 Path suffix; |
1190 Path suffix; |
1180 int markEnd = markStart + MARKER.length(); |
1191 int markEnd = markStart + MARKER.length(); |
1181 if (markEnd == seg.length()) { |
1192 if (markEnd == seg.length()) { |
1182 suffix = null; |
1193 suffix = null; |
1183 } else if (!isSeparator(seg.charAt(markEnd)) |
1194 } else if (!isSeparator(seg.charAt(markEnd)) |
1184 || seg.indexOf(MARKER, markEnd) != -1) { |
1195 || seg.indexOf(MARKER, markEnd) != -1) { |
1185 throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg); |
1196 throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg); |
1186 } else { |
1197 } else { |
1187 suffix = Paths.get(seg.substring(markEnd + 1)); |
1198 suffix = getPath(seg.substring(markEnd + 1)); |
1188 } |
1199 } |
1189 add(map, prefix, suffix); |
1200 add(map, prefix, suffix); |
1190 } |
1201 } |
1191 } |
1202 } |
1192 |
1203 |
1329 } |
1340 } |
1330 |
1341 |
1331 } |
1342 } |
1332 |
1343 |
1333 private class SystemModulesLocationHandler extends BasicLocationHandler { |
1344 private class SystemModulesLocationHandler extends BasicLocationHandler { |
1334 private Path javaHome; |
1345 private Path systemJavaHome; |
1335 private Path modules; |
1346 private Path modules; |
1336 private Map<String, ModuleLocationHandler> systemModules; |
1347 private Map<String, ModuleLocationHandler> systemModules; |
1337 |
1348 |
1338 SystemModulesLocationHandler() { |
1349 SystemModulesLocationHandler() { |
1339 super(StandardLocation.SYSTEM_MODULES, Option.SYSTEM); |
1350 super(StandardLocation.SYSTEM_MODULES, Option.SYSTEM); |
1340 javaHome = Paths.get(System.getProperty("java.home")); |
1351 systemJavaHome = Locations.javaHome; |
1341 } |
1352 } |
1342 |
1353 |
1343 @Override |
1354 @Override |
1344 boolean handleOption(Option option, String value) { |
1355 boolean handleOption(Option option, String value) { |
1345 if (!options.contains(option)) { |
1356 if (!options.contains(option)) { |
1346 return false; |
1357 return false; |
1347 } |
1358 } |
1348 |
1359 |
1349 if (value == null) { |
1360 if (value == null) { |
1350 javaHome = Paths.get(System.getProperty("java.home")); |
1361 systemJavaHome = Locations.javaHome; |
1351 } else if (value.equals("none")) { |
1362 } else if (value.equals("none")) { |
1352 javaHome = null; |
1363 systemJavaHome = null; |
1353 } else { |
1364 } else { |
1354 update(Paths.get(value)); |
1365 update(getPath(value)); |
1355 } |
1366 } |
1356 |
1367 |
1357 modules = null; |
1368 modules = null; |
1358 return true; |
1369 return true; |
1359 } |
1370 } |
1360 |
1371 |
1361 @Override |
1372 @Override |
1362 Collection<Path> getPaths() { |
1373 Collection<Path> getPaths() { |
1363 return (javaHome == null) ? null : Collections.singleton(javaHome); |
1374 return (systemJavaHome == null) ? null : Collections.singleton(systemJavaHome); |
1364 } |
1375 } |
1365 |
1376 |
1366 @Override |
1377 @Override |
1367 void setPaths(Iterable<? extends Path> files) throws IOException { |
1378 void setPaths(Iterable<? extends Path> files) throws IOException { |
1368 if (files == null) { |
1379 if (files == null) { |
1369 javaHome = null; |
1380 systemJavaHome = null; |
1370 } else { |
1381 } else { |
1371 Iterator<? extends Path> pathIter = files.iterator(); |
1382 Iterator<? extends Path> pathIter = files.iterator(); |
1372 if (!pathIter.hasNext()) { |
1383 if (!pathIter.hasNext()) { |
1373 throw new IllegalArgumentException("empty path for directory"); // TODO: FIXME |
1384 throw new IllegalArgumentException("empty path for directory"); // TODO: FIXME |
1374 } |
1385 } |
1384 update(dir); |
1395 update(dir); |
1385 } |
1396 } |
1386 } |
1397 } |
1387 |
1398 |
1388 private void update(Path p) { |
1399 private void update(Path p) { |
1389 if (!isCurrentPlatform(p) && !Files.exists(p.resolve("jrt-fs.jar")) && !Files.exists(javaHome.resolve("modules"))) |
1400 if (!isCurrentPlatform(p) && !Files.exists(p.resolve("jrt-fs.jar")) && !Files.exists(systemJavaHome.resolve("modules"))) |
1390 throw new IllegalArgumentException(p.toString()); |
1401 throw new IllegalArgumentException(p.toString()); |
1391 javaHome = p; |
1402 systemJavaHome = p; |
1392 modules = null; |
1403 modules = null; |
1393 } |
1404 } |
1394 |
1405 |
1395 private boolean isCurrentPlatform(Path p) { |
1406 private boolean isCurrentPlatform(Path p) { |
1396 Path jh = Paths.get(System.getProperty("java.home")); |
|
1397 try { |
1407 try { |
1398 return Files.isSameFile(p, jh); |
1408 return Files.isSameFile(p, Locations.javaHome); |
1399 } catch (IOException ex) { |
1409 } catch (IOException ex) { |
1400 throw new IllegalArgumentException(p.toString(), ex); |
1410 throw new IllegalArgumentException(p.toString(), ex); |
1401 } |
1411 } |
1402 } |
1412 } |
1403 |
1413 |
1419 private void initSystemModules() throws IOException { |
1429 private void initSystemModules() throws IOException { |
1420 if (systemModules != null) { |
1430 if (systemModules != null) { |
1421 return; |
1431 return; |
1422 } |
1432 } |
1423 |
1433 |
1424 if (javaHome == null) { |
1434 if (systemJavaHome == null) { |
1425 systemModules = Collections.emptyMap(); |
1435 systemModules = Collections.emptyMap(); |
1426 return; |
1436 return; |
1427 } |
1437 } |
1428 |
1438 |
1429 if (modules == null) { |
1439 if (modules == null) { |
1430 try { |
1440 try { |
1431 URI jrtURI = URI.create("jrt:/"); |
1441 URI jrtURI = URI.create("jrt:/"); |
1432 FileSystem jrtfs; |
1442 FileSystem jrtfs; |
1433 |
1443 |
1434 if (isCurrentPlatform(javaHome)) { |
1444 if (isCurrentPlatform(systemJavaHome)) { |
1435 jrtfs = FileSystems.getFileSystem(jrtURI); |
1445 jrtfs = FileSystems.getFileSystem(jrtURI); |
1436 } else { |
1446 } else { |
1437 try { |
1447 try { |
1438 Map<String, String> attrMap = |
1448 Map<String, String> attrMap = |
1439 Collections.singletonMap("java.home", javaHome.toString()); |
1449 Collections.singletonMap("java.home", systemJavaHome.toString()); |
1440 jrtfs = FileSystems.newFileSystem(jrtURI, attrMap); |
1450 jrtfs = FileSystems.newFileSystem(jrtURI, attrMap); |
1441 } catch (ProviderNotFoundException ex) { |
1451 } catch (ProviderNotFoundException ex) { |
1442 URL javaHomeURL = javaHome.resolve("jrt-fs.jar").toUri().toURL(); |
1452 URL javaHomeURL = systemJavaHome.resolve("jrt-fs.jar").toUri().toURL(); |
1443 ClassLoader currentLoader = Locations.class.getClassLoader(); |
1453 ClassLoader currentLoader = Locations.class.getClassLoader(); |
1444 URLClassLoader fsLoader = |
1454 URLClassLoader fsLoader = |
1445 new URLClassLoader(new URL[] {javaHomeURL}, currentLoader); |
1455 new URLClassLoader(new URL[] {javaHomeURL}, currentLoader); |
1446 |
1456 |
1447 jrtfs = FileSystems.newFileSystem(jrtURI, Collections.emptyMap(), fsLoader); |
1457 jrtfs = FileSystems.newFileSystem(jrtURI, Collections.emptyMap(), fsLoader); |
1452 closeables.add(jrtfs); |
1462 closeables.add(jrtfs); |
1453 } |
1463 } |
1454 |
1464 |
1455 modules = jrtfs.getPath("/modules"); |
1465 modules = jrtfs.getPath("/modules"); |
1456 } catch (FileSystemNotFoundException | ProviderNotFoundException e) { |
1466 } catch (FileSystemNotFoundException | ProviderNotFoundException e) { |
1457 modules = javaHome.resolve("modules"); |
1467 modules = systemJavaHome.resolve("modules"); |
1458 if (!Files.exists(modules)) |
1468 if (!Files.exists(modules)) |
1459 throw new IOException("can't find system classes", e); |
1469 throw new IOException("can't find system classes", e); |
1460 } |
1470 } |
1461 } |
1471 } |
1462 |
1472 |