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

Tue, 24 Dec 2013 09:17:37 -0800

author
ksrini
date
Tue, 24 Dec 2013 09:17:37 -0800
changeset 2227
998b10c43157
parent 1504
22e417cdddee
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029230: Update copyright year to match last edit in jdk8 langtools repository for 2013
Reviewed-by: ksrini
Contributed-by: steve.sides@oracle.com

     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  */
    26 package com.sun.tools.sjavac;
    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;
    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;
    66     @Override
    67     public boolean equals(Object o) {
    68         return (o instanceof Source) && name.equals(((Source)o).name);
    69     }
    71     @Override
    72     public int compareTo(Source o) {
    73         return name.compareTo(o.name);
    74     }
    76     @Override
    77     public int hashCode() {
    78         return name.hashCode();
    79     }
    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     }
    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     }
   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     }
   120     public void setPackage(Package p) {
   121         pkg = p;
   122     }
   124     public void markAsGenerated() {
   125         isGenerated = true;
   126     }
   128     public boolean isGenerated() {
   129         return isGenerated;
   130     }
   132     public void markAsLinkedOnly() {
   133         linkedOnly = true;
   134     }
   136     public boolean isLinkedOnly() {
   137         return linkedOnly;
   138     }
   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));
   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;
   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     }
   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     }
   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 {
   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);
   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     }
   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     }
   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     }
   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));
   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     }
   366     private static boolean gurka = false;
   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 {
   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         }
   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