Path: blob/master/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java
41175 views
/*1* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.sjavac;2627import java.io.File;28import java.io.IOException;29import java.nio.file.FileSystem;30import java.nio.file.FileVisitResult;31import java.nio.file.Files;32import java.nio.file.Path;33import java.nio.file.PathMatcher;34import java.nio.file.SimpleFileVisitor;35import java.nio.file.attribute.BasicFileAttributes;36import java.util.Set;37import java.util.Collections;38import java.util.List;39import java.util.ArrayList;40import java.util.Map;41import java.util.regex.PatternSyntaxException;4243/** A Source object maintains information about a source file.44* For example which package it belongs to and kind of source it is.45* The class also knows how to find source files (scanRoot) given include/exclude46* patterns and a root.47*48* <p><b>This is NOT part of any supported API.49* If you write code that depends on this, you do so at your own risk.50* This code and its internal interfaces are subject to change or51* deletion without notice.</b>52*/53public class Source implements Comparable<Source> {54// The package the source belongs to.55private Package pkg;56// Name of this source file, relative its source root.57// For example: java/lang/Object.java58// Or if the source file is inside a module:59// jdk.base/java/lang/Object.java60private String name;61// What kind of file is this.62private String suffix;63// When this source file was last_modified64private long lastModified;65// The source File.66private File file;67// If the source is generated.68private boolean isGenerated;69// If the source is only linked to, not compiled.70private boolean linkedOnly;7172@Override73public boolean equals(Object o) {74return (o instanceof Source source) && name.equals(source.name);75}7677@Override78public int compareTo(Source o) {79return name.compareTo(o.name);80}8182@Override83public int hashCode() {84return name.hashCode();85}8687public Source(Module m, String n, File f) {88name = n;89int dp = n.lastIndexOf(".");90if (dp != -1) {91suffix = n.substring(dp);92} else {93suffix = "";94}95file = f;96lastModified = f.lastModified();97linkedOnly = false;98}99100public Source(Package p, String n, long lm) {101pkg = p;102name = n;103int dp = n.lastIndexOf(".");104if (dp != -1) {105suffix = n.substring(dp);106} else {107suffix = "";108}109file = null;110lastModified = lm;111linkedOnly = false;112int ls = n.lastIndexOf('/');113}114115public String name() { return name; }116public String suffix() { return suffix; }117public Package pkg() { return pkg; }118public File file() { return file; }119public long lastModified() {120return lastModified;121}122123public void setPackage(Package p) {124pkg = p;125}126127public void markAsGenerated() {128isGenerated = true;129}130131public boolean isGenerated() {132return isGenerated;133}134135public void markAsLinkedOnly() {136linkedOnly = true;137}138139public boolean isLinkedOnly() {140return linkedOnly;141}142143private void save(StringBuilder b) {144String CL = linkedOnly?"L":"C";145String GS = isGenerated?"G":"S";146b.append(GS+" "+CL+" "+name+" "+file.lastModified()+"\n");147}148// Parse a line that looks like this:149// S C /code/alfa/A.java 1357631228000150public static Source load(Package lastPackage, String l, boolean isGenerated) {151int sp = l.indexOf(' ',4);152if (sp == -1) return null;153String name = l.substring(4,sp);154long last_modified = Long.parseLong(l.substring(sp+1));155156boolean isLinkedOnly = false;157if (l.charAt(2) == 'L') {158isLinkedOnly = true;159} else if (l.charAt(2) == 'C') {160isLinkedOnly = false;161} else return null;162163Source s = new Source(lastPackage, name, last_modified);164s.file = new File(name);165if (isGenerated) s.markAsGenerated();166if (isLinkedOnly) s.markAsLinkedOnly();167return s;168}169170public static void saveSources(Map<String,Source> sources, StringBuilder b) {171List<String> sorted_sources = new ArrayList<>();172for (String key : sources.keySet()) {173sorted_sources.add(key);174}175Collections.sort(sorted_sources);176for (String key : sorted_sources) {177Source s = sources.get(key);178s.save(b);179}180}181182/**183* Recurse into the directory root and find all files matching the excl/incl/exclfiles/inclfiles rules.184* Detects the existence of module-info.java files and presumes that the directory it resides in185* is the name of the current module.186*/187public static void scanRoot(File root,188Set<String> suffixes,189List<String> excludes,190List<String> includes,191Map<String,Source> foundFiles,192Map<String,Module> foundModules,193final Module currentModule,194boolean permitSourcesWithoutPackage,195boolean inGensrc,196boolean inLinksrc)197throws IOException, ProblemException {198199if (root == null)200return;201202FileSystem fs = root.toPath().getFileSystem();203204if (includes.isEmpty()) {205includes = Collections.singletonList("**");206}207208List<PathMatcher> includeMatchers = createPathMatchers(fs, includes);209List<PathMatcher> excludeMatchers = createPathMatchers(fs, excludes);210211Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {212@Override213public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {214215Path relToRoot = root.toPath().relativize(file);216217if (includeMatchers.stream().anyMatch(im -> im.matches(relToRoot))218&& excludeMatchers.stream().noneMatch(em -> em.matches(relToRoot))219&& suffixes.contains(Util.fileSuffix(file))) {220221// TODO: Test this.222Source existing = foundFiles.get(file);223if (existing != null) {224throw new IOException("You have already added the file "+file+" from "+existing.file().getPath());225}226existing = currentModule.lookupSource(file.toString());227if (existing != null) {228229// Oops, the source is already added, could be ok, could be not, let's check.230if (inLinksrc) {231// So we are collecting sources for linking only.232if (existing.isLinkedOnly()) {233// Ouch, this one is also for linking only. Bad.234throw new IOException("You have already added the link only file " + file + " from " + existing.file().getPath());235}236// Ok, the existing source is to be compiled. Thus this link only is redundant237// since all compiled are also linked to. Continue to the next source.238// But we need to add the source, so that it will be visible to linking,239// if not the multi core compile will fail because a JavaCompiler cannot240// find the necessary dependencies for its part of the source.241foundFiles.put(file.toString(), existing);242} else {243// We are looking for sources to compile, if we find an existing to be compiled244// source with the same name, it is an internal error, since we must245// find the sources to be compiled before we find the sources to be linked to.246throw new IOException("Internal error: Double add of file " + file + " from " + existing.file().getPath());247}248249} else {250251//////////////////////////////////////////////////////////////252// Add source253Source s = new Source(currentModule, file.toString(), file.toFile());254if (inGensrc) {255s.markAsGenerated();256}257if (inLinksrc) {258s.markAsLinkedOnly();259}260String pkg = packageOfJavaFile(root.toPath(), file);261pkg = currentModule.name() + ":" + pkg;262foundFiles.put(file.toString(), s);263currentModule.addSource(pkg, s);264//////////////////////////////////////////////////////////////265}266}267268return FileVisitResult.CONTINUE;269}270});271}272273private static List<PathMatcher> createPathMatchers(FileSystem fs, List<String> patterns) {274List<PathMatcher> matchers = new ArrayList<>();275for (String pattern : patterns) {276try {277matchers.add(fs.getPathMatcher("glob:" + pattern));278} catch (PatternSyntaxException e) {279Log.error("Invalid pattern: " + pattern);280throw e;281}282}283return matchers;284}285286private static String packageOfJavaFile(Path sourceRoot, Path javaFile) {287Path javaFileDir = javaFile.getParent();288Path packageDir = sourceRoot.relativize(javaFileDir);289List<String> separateDirs = new ArrayList<>();290for (Path pathElement : packageDir) {291separateDirs.add(pathElement.getFileName().toString());292}293return String.join(".", separateDirs);294}295296@Override297public String toString() {298return String.format("%s[pkg: %s, name: %s, suffix: %s, file: %s, isGenerated: %b, linkedOnly: %b]",299getClass().getSimpleName(),300pkg,301name,302suffix,303file,304isGenerated,305linkedOnly);306}307}308309310