Mon, 04 Feb 2013 18:08:53 -0500
Merge
ohrstrom@1504 | 1 | /* |
ohrstrom@1504 | 2 | * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. |
ohrstrom@1504 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ohrstrom@1504 | 4 | * |
ohrstrom@1504 | 5 | * This code is free software; you can redistribute it and/or modify it |
ohrstrom@1504 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohrstrom@1504 | 7 | * published by the Free Software Foundation. Oracle designates this |
ohrstrom@1504 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohrstrom@1504 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
ohrstrom@1504 | 10 | * |
ohrstrom@1504 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ohrstrom@1504 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ohrstrom@1504 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ohrstrom@1504 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
ohrstrom@1504 | 15 | * accompanied this code). |
ohrstrom@1504 | 16 | * |
ohrstrom@1504 | 17 | * You should have received a copy of the GNU General Public License version |
ohrstrom@1504 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
ohrstrom@1504 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ohrstrom@1504 | 20 | * |
ohrstrom@1504 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohrstrom@1504 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohrstrom@1504 | 23 | * questions. |
ohrstrom@1504 | 24 | */ |
ohrstrom@1504 | 25 | |
ohrstrom@1504 | 26 | package com.sun.tools.sjavac; |
ohrstrom@1504 | 27 | |
ohrstrom@1504 | 28 | import java.io.*; |
ohrstrom@1504 | 29 | import java.util.Collections; |
ohrstrom@1504 | 30 | import java.util.Date; |
ohrstrom@1504 | 31 | import java.util.Set; |
ohrstrom@1504 | 32 | import java.util.HashSet; |
ohrstrom@1504 | 33 | import java.util.List; |
ohrstrom@1504 | 34 | import java.util.Map; |
ohrstrom@1504 | 35 | import java.util.HashMap; |
ohrstrom@1504 | 36 | import java.text.SimpleDateFormat; |
ohrstrom@1504 | 37 | import java.net.URI; |
ohrstrom@1504 | 38 | import java.util.*; |
ohrstrom@1504 | 39 | |
ohrstrom@1504 | 40 | /** |
ohrstrom@1504 | 41 | * The javac state class maintains the previous (prev) and the current (now) |
ohrstrom@1504 | 42 | * build states and everything else that goes into the javac_state file. |
ohrstrom@1504 | 43 | * |
ohrstrom@1504 | 44 | * <p><b>This is NOT part of any supported API. |
ohrstrom@1504 | 45 | * If you write code that depends on this, you do so at your own |
ohrstrom@1504 | 46 | * risk. This code and its internal interfaces are subject to change |
ohrstrom@1504 | 47 | * or deletion without notice.</b></p> |
ohrstrom@1504 | 48 | */ |
ohrstrom@1504 | 49 | public class JavacState |
ohrstrom@1504 | 50 | { |
ohrstrom@1504 | 51 | // The arguments to the compile. If not identical, then it cannot |
ohrstrom@1504 | 52 | // be an incremental build! |
ohrstrom@1504 | 53 | String theArgs; |
ohrstrom@1504 | 54 | // The number of cores limits how many threads are used for heavy concurrent work. |
ohrstrom@1504 | 55 | int numCores; |
ohrstrom@1504 | 56 | |
ohrstrom@1504 | 57 | // The bin_dir/javac_state |
ohrstrom@1504 | 58 | private String javacStateFilename; |
ohrstrom@1504 | 59 | private File javacState; |
ohrstrom@1504 | 60 | |
ohrstrom@1504 | 61 | // The previous build state is loaded from javac_state |
ohrstrom@1504 | 62 | private BuildState prev; |
ohrstrom@1504 | 63 | // The current build state is constructed during the build, |
ohrstrom@1504 | 64 | // then saved as the new javac_state. |
ohrstrom@1504 | 65 | private BuildState now; |
ohrstrom@1504 | 66 | |
ohrstrom@1504 | 67 | // Something has changed in the javac_state. It needs to be saved! |
ohrstrom@1504 | 68 | private boolean needsSaving; |
ohrstrom@1504 | 69 | // If this is a new javac_state file, then do not print unnecessary messages. |
ohrstrom@1504 | 70 | private boolean newJavacState; |
ohrstrom@1504 | 71 | |
ohrstrom@1504 | 72 | // These are packages where something has changed and the package |
ohrstrom@1504 | 73 | // needs to be recompiled. Actions that trigger recompilation: |
ohrstrom@1504 | 74 | // * source belonging to the package has changed |
ohrstrom@1504 | 75 | // * artifact belonging to the package is lost, or its timestamp has been changed. |
ohrstrom@1504 | 76 | // * an unknown artifact has appeared, we simply delete it, but we also trigger a recompilation. |
ohrstrom@1504 | 77 | // * a package that is tainted, taints all packages that depend on it. |
ohrstrom@1504 | 78 | private Set<String> taintedPackages; |
ohrstrom@1504 | 79 | // After a compile, the pubapis are compared with the pubapis stored in the javac state file. |
ohrstrom@1504 | 80 | // Any packages where the pubapi differ are added to this set. |
ohrstrom@1504 | 81 | // Later we use this set and the dependency information to taint dependent packages. |
ohrstrom@1504 | 82 | private Set<String> packagesWithChangedPublicApis; |
ohrstrom@1504 | 83 | // When a module-info.java file is changed, taint the module, |
ohrstrom@1504 | 84 | // then taint all modules that depend on that that module. |
ohrstrom@1504 | 85 | // A module dependency can occur directly through a require, or |
ohrstrom@1504 | 86 | // indirectly through a module that does a public export for the first tainted module. |
ohrstrom@1504 | 87 | // When all modules are tainted, then taint all packages belonging to these modules. |
ohrstrom@1504 | 88 | // Then rebuild. It is perhaps possible (and valuable?) to do a more finegrained examination of the |
ohrstrom@1504 | 89 | // change in module-info.java, but that will have to wait. |
ohrstrom@1504 | 90 | private Set<String> taintedModules; |
ohrstrom@1504 | 91 | // The set of all packages that has been recompiled. |
ohrstrom@1504 | 92 | // Copy over the javac_state for the packages that did not need recompilation, |
ohrstrom@1504 | 93 | // verbatim from the previous (prev) to the new (now) build state. |
ohrstrom@1504 | 94 | private Set<String> recompiledPackages; |
ohrstrom@1504 | 95 | |
ohrstrom@1504 | 96 | // The output directories filled with tasty artifacts. |
ohrstrom@1504 | 97 | private File binDir, gensrcDir, headerDir; |
ohrstrom@1504 | 98 | |
ohrstrom@1504 | 99 | // The current status of the file system. |
ohrstrom@1504 | 100 | private Set<File> binArtifacts; |
ohrstrom@1504 | 101 | private Set<File> gensrcArtifacts; |
ohrstrom@1504 | 102 | private Set<File> headerArtifacts; |
ohrstrom@1504 | 103 | |
ohrstrom@1504 | 104 | // The status of the sources. |
ohrstrom@1504 | 105 | Set<Source> removedSources = null; |
ohrstrom@1504 | 106 | Set<Source> addedSources = null; |
ohrstrom@1504 | 107 | Set<Source> modifiedSources = null; |
ohrstrom@1504 | 108 | |
ohrstrom@1504 | 109 | // Visible sources for linking. These are the only |
ohrstrom@1504 | 110 | // ones that -sourcepath is allowed to see. |
ohrstrom@1504 | 111 | Set<URI> visibleSrcs; |
ohrstrom@1504 | 112 | |
ohrstrom@1504 | 113 | // Visible classes for linking. These are the only |
ohrstrom@1504 | 114 | // ones that -classpath is allowed to see. |
ohrstrom@1504 | 115 | // It maps from a classpath root to the set of visible classes for that root. |
ohrstrom@1504 | 116 | // If the set is empty, then all classes are visible for that root. |
ohrstrom@1504 | 117 | // It can also map from a jar file to the set of visible classes for that jar file. |
ohrstrom@1504 | 118 | Map<URI,Set<String>> visibleClasses; |
ohrstrom@1504 | 119 | |
ohrstrom@1504 | 120 | // Setup two transforms that always exist. |
ohrstrom@1504 | 121 | private CopyFile copyFiles = new CopyFile(); |
ohrstrom@1504 | 122 | private CompileJavaPackages compileJavaPackages = new CompileJavaPackages(); |
ohrstrom@1504 | 123 | |
ohrstrom@1504 | 124 | // Where to send stdout and stderr. |
ohrstrom@1504 | 125 | private PrintStream out, err; |
ohrstrom@1504 | 126 | |
ohrstrom@1504 | 127 | JavacState(String[] args, File bd, File gd, File hd, boolean permitUnidentifiedArtifacts, boolean removeJavacState, |
ohrstrom@1504 | 128 | PrintStream o, PrintStream e) { |
ohrstrom@1504 | 129 | out = o; |
ohrstrom@1504 | 130 | err = e; |
ohrstrom@1504 | 131 | numCores = Main.findNumberOption(args, "-j"); |
ohrstrom@1504 | 132 | theArgs = ""; |
ohrstrom@1504 | 133 | for (String a : removeArgsNotAffectingState(args)) { |
ohrstrom@1504 | 134 | theArgs = theArgs+a+" "; |
ohrstrom@1504 | 135 | } |
ohrstrom@1504 | 136 | binDir = bd; |
ohrstrom@1504 | 137 | gensrcDir = gd; |
ohrstrom@1504 | 138 | headerDir = hd; |
ohrstrom@1504 | 139 | javacStateFilename = binDir.getPath()+File.separator+"javac_state"; |
ohrstrom@1504 | 140 | javacState = new File(javacStateFilename); |
ohrstrom@1504 | 141 | if (removeJavacState && javacState.exists()) { |
ohrstrom@1504 | 142 | javacState.delete(); |
ohrstrom@1504 | 143 | } |
ohrstrom@1504 | 144 | newJavacState = false; |
ohrstrom@1504 | 145 | if (!javacState.exists()) { |
ohrstrom@1504 | 146 | newJavacState = true; |
ohrstrom@1504 | 147 | // If there is no javac_state then delete the contents of all the artifact dirs! |
ohrstrom@1504 | 148 | // We do not want to risk building a broken incremental build. |
ohrstrom@1504 | 149 | // BUT since the makefiles still copy things straight into the bin_dir et al, |
ohrstrom@1504 | 150 | // we avoid deleting files here, if the option --permit-unidentified-classes was supplied. |
ohrstrom@1504 | 151 | if (!permitUnidentifiedArtifacts) { |
ohrstrom@1504 | 152 | deleteContents(binDir); |
ohrstrom@1504 | 153 | deleteContents(gensrcDir); |
ohrstrom@1504 | 154 | deleteContents(headerDir); |
ohrstrom@1504 | 155 | } |
ohrstrom@1504 | 156 | needsSaving = true; |
ohrstrom@1504 | 157 | } |
ohrstrom@1504 | 158 | prev = new BuildState(); |
ohrstrom@1504 | 159 | now = new BuildState(); |
ohrstrom@1504 | 160 | taintedPackages = new HashSet<String>(); |
ohrstrom@1504 | 161 | recompiledPackages = new HashSet<String>(); |
ohrstrom@1504 | 162 | packagesWithChangedPublicApis = new HashSet<String>(); |
ohrstrom@1504 | 163 | } |
ohrstrom@1504 | 164 | |
ohrstrom@1504 | 165 | public BuildState prev() { return prev; } |
ohrstrom@1504 | 166 | public BuildState now() { return now; } |
ohrstrom@1504 | 167 | |
ohrstrom@1504 | 168 | /** |
ohrstrom@1504 | 169 | * Remove args not affecting the state. |
ohrstrom@1504 | 170 | */ |
ohrstrom@1504 | 171 | static String[] removeArgsNotAffectingState(String[] args) { |
ohrstrom@1504 | 172 | String[] out = new String[args.length]; |
ohrstrom@1504 | 173 | int j = 0; |
ohrstrom@1504 | 174 | for (int i = 0; i<args.length; ++i) { |
ohrstrom@1504 | 175 | if (args[i].equals("-j")) { |
ohrstrom@1504 | 176 | // Just skip it and skip following value |
ohrstrom@1504 | 177 | i++; |
ohrstrom@1504 | 178 | } else if (args[i].startsWith("--server:")) { |
ohrstrom@1504 | 179 | // Just skip it. |
ohrstrom@1504 | 180 | } else if (args[i].startsWith("--log=")) { |
ohrstrom@1504 | 181 | // Just skip it. |
ohrstrom@1504 | 182 | } else if (args[i].equals("--compare-found-sources")) { |
ohrstrom@1504 | 183 | // Just skip it and skip verify file name |
ohrstrom@1504 | 184 | i++; |
ohrstrom@1504 | 185 | } else { |
ohrstrom@1504 | 186 | // Copy argument. |
ohrstrom@1504 | 187 | out[j] = args[i]; |
ohrstrom@1504 | 188 | j++; |
ohrstrom@1504 | 189 | } |
ohrstrom@1504 | 190 | } |
ohrstrom@1504 | 191 | String[] ret = new String[j]; |
ohrstrom@1504 | 192 | System.arraycopy(out, 0, ret, 0, j); |
ohrstrom@1504 | 193 | return ret; |
ohrstrom@1504 | 194 | } |
ohrstrom@1504 | 195 | |
ohrstrom@1504 | 196 | /** |
ohrstrom@1504 | 197 | * Specify which sources are visible to the compiler through -sourcepath. |
ohrstrom@1504 | 198 | */ |
ohrstrom@1504 | 199 | public void setVisibleSources(Map<String,Source> vs) { |
ohrstrom@1504 | 200 | visibleSrcs = new HashSet<URI>(); |
ohrstrom@1504 | 201 | for (String s : vs.keySet()) { |
ohrstrom@1504 | 202 | Source src = vs.get(s); |
ohrstrom@1504 | 203 | visibleSrcs.add(src.file().toURI()); |
ohrstrom@1504 | 204 | } |
ohrstrom@1504 | 205 | } |
ohrstrom@1504 | 206 | |
ohrstrom@1504 | 207 | /** |
ohrstrom@1504 | 208 | * Specify which classes are visible to the compiler through -classpath. |
ohrstrom@1504 | 209 | */ |
ohrstrom@1504 | 210 | public void setVisibleClasses(Map<String,Source> vs) { |
ohrstrom@1504 | 211 | visibleSrcs = new HashSet<URI>(); |
ohrstrom@1504 | 212 | for (String s : vs.keySet()) { |
ohrstrom@1504 | 213 | Source src = vs.get(s); |
ohrstrom@1504 | 214 | visibleSrcs.add(src.file().toURI()); |
ohrstrom@1504 | 215 | } |
ohrstrom@1504 | 216 | } |
ohrstrom@1504 | 217 | /** |
ohrstrom@1504 | 218 | * Returns true if this is an incremental build. |
ohrstrom@1504 | 219 | */ |
ohrstrom@1504 | 220 | public boolean isIncremental() { |
ohrstrom@1504 | 221 | return !prev.sources().isEmpty(); |
ohrstrom@1504 | 222 | } |
ohrstrom@1504 | 223 | |
ohrstrom@1504 | 224 | /** |
ohrstrom@1504 | 225 | * Find all artifacts that exists on disk. |
ohrstrom@1504 | 226 | */ |
ohrstrom@1504 | 227 | public void findAllArtifacts() { |
ohrstrom@1504 | 228 | binArtifacts = findAllFiles(binDir); |
ohrstrom@1504 | 229 | gensrcArtifacts = findAllFiles(gensrcDir); |
ohrstrom@1504 | 230 | headerArtifacts = findAllFiles(headerDir); |
ohrstrom@1504 | 231 | } |
ohrstrom@1504 | 232 | |
ohrstrom@1504 | 233 | /** |
ohrstrom@1504 | 234 | * Lookup the artifacts generated for this package in the previous build. |
ohrstrom@1504 | 235 | */ |
ohrstrom@1504 | 236 | private Map<String,File> fetchPrevArtifacts(String pkg) { |
ohrstrom@1504 | 237 | Package p = prev.packages().get(pkg); |
ohrstrom@1504 | 238 | if (p != null) { |
ohrstrom@1504 | 239 | return p.artifacts(); |
ohrstrom@1504 | 240 | } |
ohrstrom@1504 | 241 | return new HashMap<String,File>(); |
ohrstrom@1504 | 242 | } |
ohrstrom@1504 | 243 | |
ohrstrom@1504 | 244 | /** |
ohrstrom@1504 | 245 | * Delete all prev artifacts in the currently tainted packages. |
ohrstrom@1504 | 246 | */ |
ohrstrom@1504 | 247 | public void deleteClassArtifactsInTaintedPackages() { |
ohrstrom@1504 | 248 | for (String pkg : taintedPackages) { |
ohrstrom@1504 | 249 | Map<String,File> arts = fetchPrevArtifacts(pkg); |
ohrstrom@1504 | 250 | for (File f : arts.values()) { |
ohrstrom@1504 | 251 | if (f.exists() && f.getName().endsWith(".class")) { |
ohrstrom@1504 | 252 | f.delete(); |
ohrstrom@1504 | 253 | } |
ohrstrom@1504 | 254 | } |
ohrstrom@1504 | 255 | } |
ohrstrom@1504 | 256 | } |
ohrstrom@1504 | 257 | |
ohrstrom@1504 | 258 | /** |
ohrstrom@1504 | 259 | * Mark the javac_state file to be in need of saving and as a side effect, |
ohrstrom@1504 | 260 | * it gets a new timestamp. |
ohrstrom@1504 | 261 | */ |
ohrstrom@1504 | 262 | private void needsSaving() { |
ohrstrom@1504 | 263 | needsSaving = true; |
ohrstrom@1504 | 264 | } |
ohrstrom@1504 | 265 | |
ohrstrom@1504 | 266 | /** |
ohrstrom@1504 | 267 | * Save the javac_state file. |
ohrstrom@1504 | 268 | */ |
ohrstrom@1504 | 269 | public void save() throws IOException { |
ohrstrom@1504 | 270 | if (!needsSaving) return; |
ohrstrom@1504 | 271 | try (FileWriter out = new FileWriter(javacStateFilename)) { |
ohrstrom@1504 | 272 | StringBuilder b = new StringBuilder(); |
ohrstrom@1504 | 273 | long millisNow = System.currentTimeMillis(); |
ohrstrom@1504 | 274 | Date d = new Date(millisNow); |
ohrstrom@1504 | 275 | SimpleDateFormat df = |
ohrstrom@1504 | 276 | new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); |
ohrstrom@1504 | 277 | b.append("# javac_state ver 0.3 generated "+millisNow+" "+df.format(d)+"\n"); |
ohrstrom@1504 | 278 | b.append("# This format might change at any time. Please do not depend on it.\n"); |
ohrstrom@1504 | 279 | b.append("# M module\n"); |
ohrstrom@1504 | 280 | b.append("# P package\n"); |
ohrstrom@1504 | 281 | b.append("# S C source_tobe_compiled timestamp\n"); |
ohrstrom@1504 | 282 | b.append("# S L link_only_source timestamp\n"); |
ohrstrom@1504 | 283 | b.append("# G C generated_source timestamp\n"); |
ohrstrom@1504 | 284 | b.append("# A artifact timestamp\n"); |
ohrstrom@1504 | 285 | b.append("# D dependency\n"); |
ohrstrom@1504 | 286 | b.append("# I pubapi\n"); |
ohrstrom@1504 | 287 | b.append("# R arguments\n"); |
ohrstrom@1504 | 288 | b.append("R ").append(theArgs).append("\n"); |
ohrstrom@1504 | 289 | |
ohrstrom@1504 | 290 | // Copy over the javac_state for the packages that did not need recompilation. |
ohrstrom@1504 | 291 | now.copyPackagesExcept(prev, recompiledPackages, new HashSet<String>()); |
ohrstrom@1504 | 292 | // Save the packages, ie package names, dependencies, pubapis and artifacts! |
ohrstrom@1504 | 293 | // I.e. the lot. |
ohrstrom@1504 | 294 | Module.saveModules(now.modules(), b); |
ohrstrom@1504 | 295 | |
ohrstrom@1504 | 296 | String s = b.toString(); |
ohrstrom@1504 | 297 | out.write(s, 0, s.length()); |
ohrstrom@1504 | 298 | } |
ohrstrom@1504 | 299 | } |
ohrstrom@1504 | 300 | |
ohrstrom@1504 | 301 | /** |
ohrstrom@1504 | 302 | * Load a javac_state file. |
ohrstrom@1504 | 303 | */ |
ohrstrom@1504 | 304 | public static JavacState load(String[] args, File binDir, File gensrcDir, File headerDir, |
ohrstrom@1504 | 305 | boolean permitUnidentifiedArtifacts, PrintStream out, PrintStream err) { |
ohrstrom@1504 | 306 | JavacState db = new JavacState(args, binDir, gensrcDir, headerDir, permitUnidentifiedArtifacts, false, out, err); |
ohrstrom@1504 | 307 | Module lastModule = null; |
ohrstrom@1504 | 308 | Package lastPackage = null; |
ohrstrom@1504 | 309 | Source lastSource = null; |
ohrstrom@1504 | 310 | boolean noFileFound = false; |
ohrstrom@1504 | 311 | boolean foundCorrectVerNr = false; |
ohrstrom@1504 | 312 | boolean newCommandLine = false; |
ohrstrom@1504 | 313 | boolean syntaxError = false; |
ohrstrom@1504 | 314 | |
ohrstrom@1504 | 315 | try (BufferedReader in = new BufferedReader(new FileReader(db.javacStateFilename))) { |
ohrstrom@1504 | 316 | for (;;) { |
ohrstrom@1504 | 317 | String l = in.readLine(); |
ohrstrom@1504 | 318 | if (l==null) break; |
ohrstrom@1504 | 319 | if (l.length()>=3 && l.charAt(1) == ' ') { |
ohrstrom@1504 | 320 | char c = l.charAt(0); |
ohrstrom@1504 | 321 | if (c == 'M') { |
ohrstrom@1504 | 322 | lastModule = db.prev.loadModule(l); |
ohrstrom@1504 | 323 | } else |
ohrstrom@1504 | 324 | if (c == 'P') { |
ohrstrom@1504 | 325 | if (lastModule == null) { syntaxError = true; break; } |
ohrstrom@1504 | 326 | lastPackage = db.prev.loadPackage(lastModule, l); |
ohrstrom@1504 | 327 | } else |
ohrstrom@1504 | 328 | if (c == 'D') { |
ohrstrom@1504 | 329 | if (lastModule == null || lastPackage == null) { syntaxError = true; break; } |
ohrstrom@1504 | 330 | lastPackage.loadDependency(l); |
ohrstrom@1504 | 331 | } else |
ohrstrom@1504 | 332 | if (c == 'I') { |
ohrstrom@1504 | 333 | if (lastModule == null || lastPackage == null) { syntaxError = true; break; } |
ohrstrom@1504 | 334 | lastPackage.loadPubapi(l); |
ohrstrom@1504 | 335 | } else |
ohrstrom@1504 | 336 | if (c == 'A') { |
ohrstrom@1504 | 337 | if (lastModule == null || lastPackage == null) { syntaxError = true; break; } |
ohrstrom@1504 | 338 | lastPackage.loadArtifact(l); |
ohrstrom@1504 | 339 | } else |
ohrstrom@1504 | 340 | if (c == 'S') { |
ohrstrom@1504 | 341 | if (lastModule == null || lastPackage == null) { syntaxError = true; break; } |
ohrstrom@1504 | 342 | lastSource = db.prev.loadSource(lastPackage, l, false); |
ohrstrom@1504 | 343 | } else |
ohrstrom@1504 | 344 | if (c == 'G') { |
ohrstrom@1504 | 345 | if (lastModule == null || lastPackage == null) { syntaxError = true; break; } |
ohrstrom@1504 | 346 | lastSource = db.prev.loadSource(lastPackage, l, true); |
ohrstrom@1504 | 347 | } else |
ohrstrom@1504 | 348 | if (c == 'R') { |
ohrstrom@1504 | 349 | String ncmdl = "R "+db.theArgs; |
ohrstrom@1504 | 350 | if (!l.equals(ncmdl)) { |
ohrstrom@1504 | 351 | newCommandLine = true; |
ohrstrom@1504 | 352 | } |
ohrstrom@1504 | 353 | } else |
ohrstrom@1504 | 354 | if (c == '#') { |
ohrstrom@1504 | 355 | if (l.startsWith("# javac_state ver ")) { |
ohrstrom@1504 | 356 | int sp = l.indexOf(" ", 18); |
ohrstrom@1504 | 357 | if (sp != -1) { |
ohrstrom@1504 | 358 | String ver = l.substring(18,sp); |
ohrstrom@1504 | 359 | if (!ver.equals("0.3")) { |
ohrstrom@1504 | 360 | break; |
ohrstrom@1504 | 361 | } |
ohrstrom@1504 | 362 | foundCorrectVerNr = true; |
ohrstrom@1504 | 363 | } |
ohrstrom@1504 | 364 | } |
ohrstrom@1504 | 365 | } |
ohrstrom@1504 | 366 | } |
ohrstrom@1504 | 367 | } |
ohrstrom@1504 | 368 | } catch (FileNotFoundException e) { |
ohrstrom@1504 | 369 | // Silently create a new javac_state file. |
ohrstrom@1504 | 370 | noFileFound = true; |
ohrstrom@1504 | 371 | } catch (IOException e) { |
ohrstrom@1504 | 372 | Log.info("Dropping old javac_state because of errors when reading it."); |
ohrstrom@1504 | 373 | db = new JavacState(args, binDir, gensrcDir, headerDir, permitUnidentifiedArtifacts, true, out, err); |
ohrstrom@1504 | 374 | foundCorrectVerNr = true; |
ohrstrom@1504 | 375 | newCommandLine = false; |
ohrstrom@1504 | 376 | syntaxError = false; |
ohrstrom@1504 | 377 | } |
ohrstrom@1504 | 378 | if (foundCorrectVerNr == false && !noFileFound) { |
ohrstrom@1504 | 379 | Log.info("Dropping old javac_state since it is of an old version."); |
ohrstrom@1504 | 380 | db = new JavacState(args, binDir, gensrcDir, headerDir, permitUnidentifiedArtifacts, true, out, err); |
ohrstrom@1504 | 381 | } else |
ohrstrom@1504 | 382 | if (newCommandLine == true && !noFileFound) { |
ohrstrom@1504 | 383 | Log.info("Dropping old javac_state since a new command line is used!"); |
ohrstrom@1504 | 384 | db = new JavacState(args, binDir, gensrcDir, headerDir, permitUnidentifiedArtifacts, true, out, err); |
ohrstrom@1504 | 385 | } else |
ohrstrom@1504 | 386 | if (syntaxError == true) { |
ohrstrom@1504 | 387 | Log.info("Dropping old javac_state since it contains syntax errors."); |
ohrstrom@1504 | 388 | db = new JavacState(args, binDir, gensrcDir, headerDir, permitUnidentifiedArtifacts, true, out, err); |
ohrstrom@1504 | 389 | } |
ohrstrom@1504 | 390 | db.prev.calculateDependents(); |
ohrstrom@1504 | 391 | return db; |
ohrstrom@1504 | 392 | } |
ohrstrom@1504 | 393 | |
ohrstrom@1504 | 394 | /** |
ohrstrom@1504 | 395 | * Mark a java package as tainted, ie it needs recompilation. |
ohrstrom@1504 | 396 | */ |
ohrstrom@1504 | 397 | public void taintPackage(String name, String because) { |
ohrstrom@1504 | 398 | if (!taintedPackages.contains(name)) { |
ohrstrom@1504 | 399 | if (because != null) Log.debug("Tainting "+Util.justPackageName(name)+" because "+because); |
ohrstrom@1504 | 400 | // It has not been tainted before. |
ohrstrom@1504 | 401 | taintedPackages.add(name); |
ohrstrom@1504 | 402 | needsSaving(); |
ohrstrom@1504 | 403 | Package nowp = now.packages().get(name); |
ohrstrom@1504 | 404 | if (nowp != null) { |
ohrstrom@1504 | 405 | for (String d : nowp.dependents()) { |
ohrstrom@1504 | 406 | taintPackage(d, because); |
ohrstrom@1504 | 407 | } |
ohrstrom@1504 | 408 | } |
ohrstrom@1504 | 409 | } |
ohrstrom@1504 | 410 | } |
ohrstrom@1504 | 411 | |
ohrstrom@1504 | 412 | /** |
ohrstrom@1504 | 413 | * This packages need recompilation. |
ohrstrom@1504 | 414 | */ |
ohrstrom@1504 | 415 | public Set<String> taintedPackages() { |
ohrstrom@1504 | 416 | return taintedPackages; |
ohrstrom@1504 | 417 | } |
ohrstrom@1504 | 418 | |
ohrstrom@1504 | 419 | /** |
ohrstrom@1504 | 420 | * Clean out the tainted package set, used after the first round of compiles, |
ohrstrom@1504 | 421 | * prior to propagating dependencies. |
ohrstrom@1504 | 422 | */ |
ohrstrom@1504 | 423 | public void clearTaintedPackages() { |
ohrstrom@1504 | 424 | taintedPackages = new HashSet<String>(); |
ohrstrom@1504 | 425 | } |
ohrstrom@1504 | 426 | |
ohrstrom@1504 | 427 | /** |
ohrstrom@1504 | 428 | * Go through all sources and check which have been removed, added or modified |
ohrstrom@1504 | 429 | * and taint the corresponding packages. |
ohrstrom@1504 | 430 | */ |
ohrstrom@1504 | 431 | public void checkSourceStatus(boolean check_gensrc) { |
ohrstrom@1504 | 432 | removedSources = calculateRemovedSources(); |
ohrstrom@1504 | 433 | for (Source s : removedSources) { |
ohrstrom@1504 | 434 | if (!s.isGenerated() || check_gensrc) { |
ohrstrom@1504 | 435 | taintPackage(s.pkg().name(), "source "+s.name()+" was removed"); |
ohrstrom@1504 | 436 | } |
ohrstrom@1504 | 437 | } |
ohrstrom@1504 | 438 | |
ohrstrom@1504 | 439 | addedSources = calculateAddedSources(); |
ohrstrom@1504 | 440 | for (Source s : addedSources) { |
ohrstrom@1504 | 441 | String msg = null; |
ohrstrom@1504 | 442 | if (isIncremental()) { |
ohrstrom@1504 | 443 | // When building from scratch, there is no point |
ohrstrom@1504 | 444 | // printing "was added" for every file since all files are added. |
ohrstrom@1504 | 445 | // However for an incremental build it makes sense. |
ohrstrom@1504 | 446 | msg = "source "+s.name()+" was added"; |
ohrstrom@1504 | 447 | } |
ohrstrom@1504 | 448 | if (!s.isGenerated() || check_gensrc) { |
ohrstrom@1504 | 449 | taintPackage(s.pkg().name(), msg); |
ohrstrom@1504 | 450 | } |
ohrstrom@1504 | 451 | } |
ohrstrom@1504 | 452 | |
ohrstrom@1504 | 453 | modifiedSources = calculateModifiedSources(); |
ohrstrom@1504 | 454 | for (Source s : modifiedSources) { |
ohrstrom@1504 | 455 | if (!s.isGenerated() || check_gensrc) { |
ohrstrom@1504 | 456 | taintPackage(s.pkg().name(), "source "+s.name()+" was modified"); |
ohrstrom@1504 | 457 | } |
ohrstrom@1504 | 458 | } |
ohrstrom@1504 | 459 | } |
ohrstrom@1504 | 460 | |
ohrstrom@1504 | 461 | /** |
ohrstrom@1504 | 462 | * Acquire the compile_java_packages suffix rule for .java files. |
ohrstrom@1504 | 463 | */ |
ohrstrom@1504 | 464 | public Map<String,Transformer> getJavaSuffixRule() { |
ohrstrom@1504 | 465 | Map<String,Transformer> sr = new HashMap<String,Transformer>(); |
ohrstrom@1504 | 466 | sr.put(".java", compileJavaPackages); |
ohrstrom@1504 | 467 | return sr; |
ohrstrom@1504 | 468 | } |
ohrstrom@1504 | 469 | |
ohrstrom@1504 | 470 | /** |
ohrstrom@1504 | 471 | * Acquire the copying transform. |
ohrstrom@1504 | 472 | */ |
ohrstrom@1504 | 473 | public Transformer getCopier() { |
ohrstrom@1504 | 474 | return copyFiles; |
ohrstrom@1504 | 475 | } |
ohrstrom@1504 | 476 | |
ohrstrom@1504 | 477 | /** |
ohrstrom@1504 | 478 | * If artifacts have gone missing, force a recompile of the packages |
ohrstrom@1504 | 479 | * they belong to. |
ohrstrom@1504 | 480 | */ |
ohrstrom@1504 | 481 | public void taintPackagesThatMissArtifacts() { |
ohrstrom@1504 | 482 | for (Package pkg : prev.packages().values()) { |
ohrstrom@1504 | 483 | for (File f : pkg.artifacts().values()) { |
ohrstrom@1504 | 484 | if (!f.exists()) { |
ohrstrom@1504 | 485 | // Hmm, the artifact on disk does not exist! Someone has removed it.... |
ohrstrom@1504 | 486 | // Lets rebuild the package. |
ohrstrom@1504 | 487 | taintPackage(pkg.name(), ""+f+" is missing."); |
ohrstrom@1504 | 488 | } |
ohrstrom@1504 | 489 | } |
ohrstrom@1504 | 490 | } |
ohrstrom@1504 | 491 | } |
ohrstrom@1504 | 492 | |
ohrstrom@1504 | 493 | /** |
ohrstrom@1504 | 494 | * Propagate recompilation through the dependency chains. |
ohrstrom@1504 | 495 | * Avoid re-tainting packages that have already been compiled. |
ohrstrom@1504 | 496 | */ |
ohrstrom@1504 | 497 | public void taintPackagesDependingOnChangedPackages(Set<String> pkgs, Set<String> recentlyCompiled) { |
ohrstrom@1504 | 498 | for (Package pkg : prev.packages().values()) { |
ohrstrom@1504 | 499 | for (String dep : pkg.dependencies()) { |
ohrstrom@1504 | 500 | if (pkgs.contains(dep) && !recentlyCompiled.contains(pkg.name())) { |
ohrstrom@1504 | 501 | taintPackage(pkg.name(), " its depending on "+dep); |
ohrstrom@1504 | 502 | } |
ohrstrom@1504 | 503 | } |
ohrstrom@1504 | 504 | } |
ohrstrom@1504 | 505 | } |
ohrstrom@1504 | 506 | |
ohrstrom@1504 | 507 | /** |
ohrstrom@1504 | 508 | * Scan all output dirs for artifacts and remove those files (artifacts?) |
ohrstrom@1504 | 509 | * that are not recognized as such, in the javac_state file. |
ohrstrom@1504 | 510 | */ |
ohrstrom@1504 | 511 | public void removeUnidentifiedArtifacts() { |
ohrstrom@1504 | 512 | Set<File> allKnownArtifacts = new HashSet<File>(); |
ohrstrom@1504 | 513 | for (Package pkg : prev.packages().values()) { |
ohrstrom@1504 | 514 | for (File f : pkg.artifacts().values()) { |
ohrstrom@1504 | 515 | allKnownArtifacts.add(f); |
ohrstrom@1504 | 516 | } |
ohrstrom@1504 | 517 | } |
ohrstrom@1504 | 518 | // Do not forget about javac_state.... |
ohrstrom@1504 | 519 | allKnownArtifacts.add(javacState); |
ohrstrom@1504 | 520 | |
ohrstrom@1504 | 521 | for (File f : binArtifacts) { |
ohrstrom@1504 | 522 | if (!allKnownArtifacts.contains(f)) { |
ohrstrom@1504 | 523 | Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state."); |
ohrstrom@1504 | 524 | f.delete(); |
ohrstrom@1504 | 525 | } |
ohrstrom@1504 | 526 | } |
ohrstrom@1504 | 527 | for (File f : headerArtifacts) { |
ohrstrom@1504 | 528 | if (!allKnownArtifacts.contains(f)) { |
ohrstrom@1504 | 529 | Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state."); |
ohrstrom@1504 | 530 | f.delete(); |
ohrstrom@1504 | 531 | } |
ohrstrom@1504 | 532 | } |
ohrstrom@1504 | 533 | for (File f : gensrcArtifacts) { |
ohrstrom@1504 | 534 | if (!allKnownArtifacts.contains(f)) { |
ohrstrom@1504 | 535 | Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state."); |
ohrstrom@1504 | 536 | f.delete(); |
ohrstrom@1504 | 537 | } |
ohrstrom@1504 | 538 | } |
ohrstrom@1504 | 539 | } |
ohrstrom@1504 | 540 | |
ohrstrom@1504 | 541 | /** |
ohrstrom@1504 | 542 | * Remove artifacts that are no longer produced when compiling! |
ohrstrom@1504 | 543 | */ |
ohrstrom@1504 | 544 | public void removeSuperfluousArtifacts(Set<String> recentlyCompiled) { |
ohrstrom@1504 | 545 | // Nothing to do, if nothing was recompiled. |
ohrstrom@1504 | 546 | if (recentlyCompiled.size() == 0) return; |
ohrstrom@1504 | 547 | |
ohrstrom@1504 | 548 | for (String pkg : now.packages().keySet()) { |
ohrstrom@1504 | 549 | // If this package has not been recompiled, skip the check. |
ohrstrom@1504 | 550 | if (!recentlyCompiled.contains(pkg)) continue; |
ohrstrom@1504 | 551 | Collection<File> arts = now.artifacts().values(); |
ohrstrom@1504 | 552 | for (File f : fetchPrevArtifacts(pkg).values()) { |
ohrstrom@1504 | 553 | if (!arts.contains(f)) { |
ohrstrom@1504 | 554 | Log.debug("Removing "+f.getPath()+" since it is now superfluous!"); |
ohrstrom@1504 | 555 | if (f.exists()) f.delete(); |
ohrstrom@1504 | 556 | } |
ohrstrom@1504 | 557 | } |
ohrstrom@1504 | 558 | } |
ohrstrom@1504 | 559 | } |
ohrstrom@1504 | 560 | |
ohrstrom@1504 | 561 | /** |
ohrstrom@1504 | 562 | * Return those files belonging to prev, but not now. |
ohrstrom@1504 | 563 | */ |
ohrstrom@1504 | 564 | private Set<Source> calculateRemovedSources() { |
ohrstrom@1504 | 565 | Set<Source> removed = new HashSet<Source>(); |
ohrstrom@1504 | 566 | for (String src : prev.sources().keySet()) { |
ohrstrom@1504 | 567 | if (now.sources().get(src) == null) { |
ohrstrom@1504 | 568 | removed.add(prev.sources().get(src)); |
ohrstrom@1504 | 569 | } |
ohrstrom@1504 | 570 | } |
ohrstrom@1504 | 571 | return removed; |
ohrstrom@1504 | 572 | } |
ohrstrom@1504 | 573 | |
ohrstrom@1504 | 574 | /** |
ohrstrom@1504 | 575 | * Return those files belonging to now, but not prev. |
ohrstrom@1504 | 576 | */ |
ohrstrom@1504 | 577 | private Set<Source> calculateAddedSources() { |
ohrstrom@1504 | 578 | Set<Source> added = new HashSet<Source>(); |
ohrstrom@1504 | 579 | for (String src : now.sources().keySet()) { |
ohrstrom@1504 | 580 | if (prev.sources().get(src) == null) { |
ohrstrom@1504 | 581 | added.add(now.sources().get(src)); |
ohrstrom@1504 | 582 | } |
ohrstrom@1504 | 583 | } |
ohrstrom@1504 | 584 | return added; |
ohrstrom@1504 | 585 | } |
ohrstrom@1504 | 586 | |
ohrstrom@1504 | 587 | /** |
ohrstrom@1504 | 588 | * Return those files where the timestamp is newer. |
ohrstrom@1504 | 589 | * If a source file timestamp suddenly is older than what is known |
ohrstrom@1504 | 590 | * about it in javac_state, then consider it modified, but print |
ohrstrom@1504 | 591 | * a warning! |
ohrstrom@1504 | 592 | */ |
ohrstrom@1504 | 593 | private Set<Source> calculateModifiedSources() { |
ohrstrom@1504 | 594 | Set<Source> modified = new HashSet<Source>(); |
ohrstrom@1504 | 595 | for (String src : now.sources().keySet()) { |
ohrstrom@1504 | 596 | Source n = now.sources().get(src); |
ohrstrom@1504 | 597 | Source t = prev.sources().get(src); |
ohrstrom@1504 | 598 | if (prev.sources().get(src) != null) { |
ohrstrom@1504 | 599 | if (t != null) { |
ohrstrom@1504 | 600 | if (n.lastModified() > t.lastModified()) { |
ohrstrom@1504 | 601 | modified.add(n); |
ohrstrom@1504 | 602 | } else if (n.lastModified() < t.lastModified()) { |
ohrstrom@1504 | 603 | modified.add(n); |
ohrstrom@1504 | 604 | Log.warn("The source file "+n.name()+" timestamp has moved backwards in time."); |
ohrstrom@1504 | 605 | } |
ohrstrom@1504 | 606 | } |
ohrstrom@1504 | 607 | } |
ohrstrom@1504 | 608 | } |
ohrstrom@1504 | 609 | return modified; |
ohrstrom@1504 | 610 | } |
ohrstrom@1504 | 611 | |
ohrstrom@1504 | 612 | /** |
ohrstrom@1504 | 613 | * Recursively delete a directory and all its contents. |
ohrstrom@1504 | 614 | */ |
ohrstrom@1504 | 615 | private static void deleteContents(File dir) { |
ohrstrom@1504 | 616 | if (dir != null && dir.exists()) { |
ohrstrom@1504 | 617 | for (File f : dir.listFiles()) { |
ohrstrom@1504 | 618 | if (f.isDirectory()) { |
ohrstrom@1504 | 619 | deleteContents(f); |
ohrstrom@1504 | 620 | } |
ohrstrom@1504 | 621 | f.delete(); |
ohrstrom@1504 | 622 | } |
ohrstrom@1504 | 623 | } |
ohrstrom@1504 | 624 | } |
ohrstrom@1504 | 625 | |
ohrstrom@1504 | 626 | /** |
ohrstrom@1504 | 627 | * Run the copy translator only. |
ohrstrom@1504 | 628 | */ |
ohrstrom@1504 | 629 | public void performCopying(File binDir, Map<String,Transformer> suffixRules) { |
ohrstrom@1504 | 630 | Map<String,Transformer> sr = new HashMap<String,Transformer>(); |
ohrstrom@1504 | 631 | for (Map.Entry<String,Transformer> e : suffixRules.entrySet()) { |
ohrstrom@1504 | 632 | if (e.getValue() == copyFiles) { |
ohrstrom@1504 | 633 | sr.put(e.getKey(), e.getValue()); |
ohrstrom@1504 | 634 | } |
ohrstrom@1504 | 635 | } |
ohrstrom@1504 | 636 | perform(binDir, sr); |
ohrstrom@1504 | 637 | } |
ohrstrom@1504 | 638 | |
ohrstrom@1504 | 639 | /** |
ohrstrom@1504 | 640 | * Run all the translators that translate into java source code. |
ohrstrom@1504 | 641 | * I.e. all translators that are not copy nor compile_java_source. |
ohrstrom@1504 | 642 | */ |
ohrstrom@1504 | 643 | public void performTranslation(File gensrcDir, Map<String,Transformer> suffixRules) { |
ohrstrom@1504 | 644 | Map<String,Transformer> sr = new HashMap<String,Transformer>(); |
ohrstrom@1504 | 645 | for (Map.Entry<String,Transformer> e : suffixRules.entrySet()) { |
ohrstrom@1504 | 646 | if (e.getValue() != copyFiles && |
ohrstrom@1504 | 647 | e.getValue() != compileJavaPackages) { |
ohrstrom@1504 | 648 | sr.put(e.getKey(), e.getValue()); |
ohrstrom@1504 | 649 | } |
ohrstrom@1504 | 650 | } |
ohrstrom@1504 | 651 | perform(gensrcDir, sr); |
ohrstrom@1504 | 652 | } |
ohrstrom@1504 | 653 | |
ohrstrom@1504 | 654 | /** |
ohrstrom@1504 | 655 | * Compile all the java sources. Return true, if it needs to be called again! |
ohrstrom@1504 | 656 | */ |
ohrstrom@1504 | 657 | public boolean performJavaCompilations(File binDir, |
ohrstrom@1504 | 658 | String serverSettings, |
ohrstrom@1504 | 659 | String[] args, |
ohrstrom@1504 | 660 | Set<String> recentlyCompiled, |
ohrstrom@1504 | 661 | boolean[] rcValue) { |
ohrstrom@1504 | 662 | Map<String,Transformer> suffixRules = new HashMap<String,Transformer>(); |
ohrstrom@1504 | 663 | suffixRules.put(".java", compileJavaPackages); |
ohrstrom@1504 | 664 | compileJavaPackages.setExtra(serverSettings); |
ohrstrom@1504 | 665 | compileJavaPackages.setExtra(args); |
ohrstrom@1504 | 666 | |
ohrstrom@1504 | 667 | rcValue[0] = perform(binDir, suffixRules); |
ohrstrom@1504 | 668 | recentlyCompiled.addAll(taintedPackages()); |
ohrstrom@1504 | 669 | clearTaintedPackages(); |
ohrstrom@1504 | 670 | boolean again = !packagesWithChangedPublicApis.isEmpty(); |
ohrstrom@1504 | 671 | taintPackagesDependingOnChangedPackages(packagesWithChangedPublicApis, recentlyCompiled); |
ohrstrom@1504 | 672 | packagesWithChangedPublicApis = new HashSet<String>(); |
ohrstrom@1504 | 673 | return again && rcValue[0]; |
ohrstrom@1504 | 674 | } |
ohrstrom@1504 | 675 | |
ohrstrom@1504 | 676 | /** |
ohrstrom@1504 | 677 | * Store the source into the set of sources belonging to the given transform. |
ohrstrom@1504 | 678 | */ |
ohrstrom@1504 | 679 | private void addFileToTransform(Map<Transformer,Map<String,Set<URI>>> gs, Transformer t, Source s) { |
ohrstrom@1504 | 680 | Map<String,Set<URI>> fs = gs.get(t); |
ohrstrom@1504 | 681 | if (fs == null) { |
ohrstrom@1504 | 682 | fs = new HashMap<String,Set<URI>>(); |
ohrstrom@1504 | 683 | gs.put(t, fs); |
ohrstrom@1504 | 684 | } |
ohrstrom@1504 | 685 | Set<URI> ss = fs.get(s.pkg().name()); |
ohrstrom@1504 | 686 | if (ss == null) { |
ohrstrom@1504 | 687 | ss = new HashSet<URI>(); |
ohrstrom@1504 | 688 | fs.put(s.pkg().name(), ss); |
ohrstrom@1504 | 689 | } |
ohrstrom@1504 | 690 | ss.add(s.file().toURI()); |
ohrstrom@1504 | 691 | } |
ohrstrom@1504 | 692 | |
ohrstrom@1504 | 693 | /** |
ohrstrom@1504 | 694 | * For all packages, find all sources belonging to the package, group the sources |
ohrstrom@1504 | 695 | * based on their transformers and apply the transformers on each source code group. |
ohrstrom@1504 | 696 | */ |
ohrstrom@1504 | 697 | private boolean perform(File outputDir, Map<String,Transformer> suffixRules) |
ohrstrom@1504 | 698 | { |
ohrstrom@1504 | 699 | boolean rc = true; |
ohrstrom@1504 | 700 | // Group sources based on transforms. A source file can only belong to a single transform. |
ohrstrom@1504 | 701 | Map<Transformer,Map<String,Set<URI>>> groupedSources = new HashMap<Transformer,Map<String,Set<URI>>>(); |
ohrstrom@1504 | 702 | for (Source src : now.sources().values()) { |
ohrstrom@1504 | 703 | Transformer t = suffixRules.get(src.suffix()); |
ohrstrom@1504 | 704 | if (t != null) { |
ohrstrom@1504 | 705 | if (taintedPackages.contains(src.pkg().name()) && !src.isLinkedOnly()) { |
ohrstrom@1504 | 706 | addFileToTransform(groupedSources, t, src); |
ohrstrom@1504 | 707 | } |
ohrstrom@1504 | 708 | } |
ohrstrom@1504 | 709 | } |
ohrstrom@1504 | 710 | // Go through the transforms and transform them. |
ohrstrom@1504 | 711 | for (Map.Entry<Transformer,Map<String,Set<URI>>> e : groupedSources.entrySet()) { |
ohrstrom@1504 | 712 | Transformer t = e.getKey(); |
ohrstrom@1504 | 713 | Map<String,Set<URI>> srcs = e.getValue(); |
ohrstrom@1504 | 714 | // These maps need to be synchronized since multiple threads will be writing results into them. |
ohrstrom@1504 | 715 | Map<String,Set<URI>> packageArtifacts = Collections.synchronizedMap(new HashMap<String,Set<URI>>()); |
ohrstrom@1504 | 716 | Map<String,Set<String>> packageDependencies = Collections.synchronizedMap(new HashMap<String,Set<String>>()); |
ohrstrom@1504 | 717 | Map<String,String> packagePublicApis = Collections.synchronizedMap(new HashMap<String,String>()); |
ohrstrom@1504 | 718 | |
ohrstrom@1504 | 719 | boolean r = t.transform(srcs, |
ohrstrom@1504 | 720 | visibleSrcs, |
ohrstrom@1504 | 721 | visibleClasses, |
ohrstrom@1504 | 722 | prev.dependents(), |
ohrstrom@1504 | 723 | outputDir.toURI(), |
ohrstrom@1504 | 724 | packageArtifacts, |
ohrstrom@1504 | 725 | packageDependencies, |
ohrstrom@1504 | 726 | packagePublicApis, |
ohrstrom@1504 | 727 | 0, |
ohrstrom@1504 | 728 | isIncremental(), |
ohrstrom@1504 | 729 | numCores, |
ohrstrom@1504 | 730 | out, |
ohrstrom@1504 | 731 | err); |
ohrstrom@1504 | 732 | if (!r) rc = false; |
ohrstrom@1504 | 733 | |
ohrstrom@1504 | 734 | for (String p : srcs.keySet()) { |
ohrstrom@1504 | 735 | recompiledPackages.add(p); |
ohrstrom@1504 | 736 | } |
ohrstrom@1504 | 737 | // The transform is done! Extract all the artifacts and store the info into the Package objects. |
ohrstrom@1504 | 738 | for (Map.Entry<String,Set<URI>> a : packageArtifacts.entrySet()) { |
ohrstrom@1504 | 739 | Module mnow = now.findModuleFromPackageName(a.getKey()); |
ohrstrom@1504 | 740 | mnow.addArtifacts(a.getKey(), a.getValue()); |
ohrstrom@1504 | 741 | } |
ohrstrom@1504 | 742 | // Extract all the dependencies and store the info into the Package objects. |
ohrstrom@1504 | 743 | for (Map.Entry<String,Set<String>> a : packageDependencies.entrySet()) { |
ohrstrom@1504 | 744 | Set<String> deps = a.getValue(); |
ohrstrom@1504 | 745 | Module mnow = now.findModuleFromPackageName(a.getKey()); |
ohrstrom@1504 | 746 | mnow.setDependencies(a.getKey(), deps); |
ohrstrom@1504 | 747 | } |
ohrstrom@1504 | 748 | // Extract all the pubapis and store the info into the Package objects. |
ohrstrom@1504 | 749 | for (Map.Entry<String,String> a : packagePublicApis.entrySet()) { |
ohrstrom@1504 | 750 | Module mprev = prev.findModuleFromPackageName(a.getKey()); |
ohrstrom@1504 | 751 | List<String> pubapi = Package.pubapiToList(a.getValue()); |
ohrstrom@1504 | 752 | Module mnow = now.findModuleFromPackageName(a.getKey()); |
ohrstrom@1504 | 753 | mnow.setPubapi(a.getKey(), pubapi); |
ohrstrom@1504 | 754 | if (mprev.hasPubapiChanged(a.getKey(), pubapi)) { |
ohrstrom@1504 | 755 | // Aha! The pubapi of this package has changed! |
ohrstrom@1504 | 756 | // It can also be a new compile from scratch. |
ohrstrom@1504 | 757 | if (mprev.lookupPackage(a.getKey()).existsInJavacState()) { |
ohrstrom@1504 | 758 | // This is an incremental compile! The pubapi |
ohrstrom@1504 | 759 | // did change. Trigger recompilation of dependents. |
ohrstrom@1504 | 760 | packagesWithChangedPublicApis.add(a.getKey()); |
ohrstrom@1504 | 761 | Log.info("The pubapi of "+Util.justPackageName(a.getKey())+" has changed!"); |
ohrstrom@1504 | 762 | } |
ohrstrom@1504 | 763 | } |
ohrstrom@1504 | 764 | } |
ohrstrom@1504 | 765 | } |
ohrstrom@1504 | 766 | return rc; |
ohrstrom@1504 | 767 | } |
ohrstrom@1504 | 768 | |
ohrstrom@1504 | 769 | /** |
ohrstrom@1504 | 770 | * Utility method to recursively find all files below a directory. |
ohrstrom@1504 | 771 | */ |
ohrstrom@1504 | 772 | private static Set<File> findAllFiles(File dir) { |
ohrstrom@1504 | 773 | Set<File> foundFiles = new HashSet<File>(); |
ohrstrom@1504 | 774 | if (dir == null) { |
ohrstrom@1504 | 775 | return foundFiles; |
ohrstrom@1504 | 776 | } |
ohrstrom@1504 | 777 | recurse(dir, foundFiles); |
ohrstrom@1504 | 778 | return foundFiles; |
ohrstrom@1504 | 779 | } |
ohrstrom@1504 | 780 | |
ohrstrom@1504 | 781 | private static void recurse(File dir, Set<File> foundFiles) { |
ohrstrom@1504 | 782 | for (File f : dir.listFiles()) { |
ohrstrom@1504 | 783 | if (f.isFile()) { |
ohrstrom@1504 | 784 | foundFiles.add(f); |
ohrstrom@1504 | 785 | } else if (f.isDirectory()) { |
ohrstrom@1504 | 786 | recurse(f, foundFiles); |
ohrstrom@1504 | 787 | } |
ohrstrom@1504 | 788 | } |
ohrstrom@1504 | 789 | } |
ohrstrom@1504 | 790 | |
ohrstrom@1504 | 791 | /** |
ohrstrom@1504 | 792 | * Compare the calculate source list, with an explicit list, usually supplied from the makefile. |
ohrstrom@1504 | 793 | * Used to detect bugs where the makefile and sjavac have different opinions on which files |
ohrstrom@1504 | 794 | * should be compiled. |
ohrstrom@1504 | 795 | */ |
ohrstrom@1504 | 796 | public void compareWithMakefileList(File makefileSourceList) |
ohrstrom@1504 | 797 | throws ProblemException |
ohrstrom@1504 | 798 | { |
ohrstrom@1504 | 799 | // If we are building on win32 using for example cygwin the paths in the makefile source list |
ohrstrom@1504 | 800 | // might be /cygdrive/c/.... which does not match c:\.... |
ohrstrom@1504 | 801 | // We need to adjust our calculated sources to be identical, if necessary. |
ohrstrom@1504 | 802 | boolean mightNeedRewriting = File.pathSeparatorChar == ';'; |
ohrstrom@1504 | 803 | |
ohrstrom@1504 | 804 | if (makefileSourceList == null) return; |
ohrstrom@1504 | 805 | |
ohrstrom@1504 | 806 | Set<String> calculatedSources = new HashSet<String>(); |
ohrstrom@1504 | 807 | Set<String> listedSources = new HashSet<String>(); |
ohrstrom@1504 | 808 | |
ohrstrom@1504 | 809 | // Create a set of filenames with full paths. |
ohrstrom@1504 | 810 | for (Source s : now.sources().values()) { |
ohrstrom@1504 | 811 | calculatedSources.add(s.file().getPath()); |
ohrstrom@1504 | 812 | } |
ohrstrom@1504 | 813 | // Read in the file and create another set of filenames with full paths. |
ohrstrom@1504 | 814 | try { |
ohrstrom@1504 | 815 | BufferedReader in = new BufferedReader(new FileReader(makefileSourceList)); |
ohrstrom@1504 | 816 | for (;;) { |
ohrstrom@1504 | 817 | String l = in.readLine(); |
ohrstrom@1504 | 818 | if (l==null) break; |
ohrstrom@1504 | 819 | l = l.trim(); |
ohrstrom@1504 | 820 | if (mightNeedRewriting) { |
ohrstrom@1504 | 821 | if (l.indexOf(":") == 1 && l.indexOf("\\") == 2) { |
ohrstrom@1504 | 822 | // Everything a-ok, the format is already C:\foo\bar |
ohrstrom@1504 | 823 | } else if (l.indexOf(":") == 1 && l.indexOf("/") == 2) { |
ohrstrom@1504 | 824 | // The format is C:/foo/bar, rewrite into the above format. |
ohrstrom@1504 | 825 | l = l.replaceAll("/","\\\\"); |
ohrstrom@1504 | 826 | } else if (l.charAt(0) == '/' && l.indexOf("/",1) != -1) { |
ohrstrom@1504 | 827 | // The format might be: /cygdrive/c/foo/bar, rewrite into the above format. |
ohrstrom@1504 | 828 | // Do not hardcode the name cygdrive here. |
ohrstrom@1504 | 829 | int slash = l.indexOf("/",1); |
ohrstrom@1504 | 830 | l = l.replaceAll("/","\\\\"); |
ohrstrom@1504 | 831 | l = ""+l.charAt(slash+1)+":"+l.substring(slash+2); |
ohrstrom@1504 | 832 | } |
ohrstrom@1504 | 833 | if (Character.isLowerCase(l.charAt(0))) { |
ohrstrom@1504 | 834 | l = Character.toUpperCase(l.charAt(0))+l.substring(1); |
ohrstrom@1504 | 835 | } |
ohrstrom@1504 | 836 | } |
ohrstrom@1504 | 837 | listedSources.add(l); |
ohrstrom@1504 | 838 | } |
ohrstrom@1504 | 839 | } catch (FileNotFoundException e) { |
ohrstrom@1504 | 840 | throw new ProblemException("Could not open "+makefileSourceList.getPath()+" since it does not exist!"); |
ohrstrom@1504 | 841 | } catch (IOException e) { |
ohrstrom@1504 | 842 | throw new ProblemException("Could not read "+makefileSourceList.getPath()); |
ohrstrom@1504 | 843 | } |
ohrstrom@1504 | 844 | |
ohrstrom@1504 | 845 | for (String s : listedSources) { |
ohrstrom@1504 | 846 | if (!calculatedSources.contains(s)) { |
ohrstrom@1504 | 847 | throw new ProblemException("The makefile listed source "+s+" was not calculated by the smart javac wrapper!"); |
ohrstrom@1504 | 848 | } |
ohrstrom@1504 | 849 | } |
ohrstrom@1504 | 850 | |
ohrstrom@1504 | 851 | for (String s : calculatedSources) { |
ohrstrom@1504 | 852 | if (!listedSources.contains(s)) { |
ohrstrom@1504 | 853 | throw new ProblemException("The smart javac wrapper calculated source "+s+" was not listed by the makefiles!"); |
ohrstrom@1504 | 854 | } |
ohrstrom@1504 | 855 | } |
ohrstrom@1504 | 856 | } |
ohrstrom@1504 | 857 | } |