| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 package com.google.dart.compiler; | 4 package com.google.dart.compiler; |
| 6 | 5 |
| 6 import com.google.common.base.Objects; |
| 7 import com.google.common.base.Splitter; |
| 8 import com.google.common.base.Strings; |
| 9 import com.google.common.collect.Iterables; |
| 10 import com.google.common.collect.Maps; |
| 11 import com.google.common.collect.Sets; |
| 7 import com.google.dart.compiler.ast.DartUnit; | 12 import com.google.dart.compiler.ast.DartUnit; |
| 8 | 13 |
| 9 import java.io.BufferedReader; | 14 import java.io.BufferedReader; |
| 10 import java.io.IOException; | 15 import java.io.IOException; |
| 11 import java.io.Reader; | 16 import java.io.Reader; |
| 12 import java.io.StringWriter; | |
| 13 import java.io.Writer; | 17 import java.io.Writer; |
| 14 import java.net.URI; | 18 import java.net.URI; |
| 15 import java.net.URISyntaxException; | 19 import java.util.List; |
| 16 import java.util.ArrayList; | |
| 17 import java.util.Collections; | |
| 18 import java.util.Map; | 20 import java.util.Map; |
| 19 import java.util.concurrent.ConcurrentHashMap; | 21 import java.util.Map.Entry; |
| 22 import java.util.Set; |
| 20 | 23 |
| 21 /** | 24 /** |
| 22 * Represents a library's dependencies artifact. | 25 * Represents a library's dependencies artifact. |
| 23 */ | 26 */ |
| 24 public class LibraryDeps { | 27 public class LibraryDeps { |
| 25 | 28 private static final String VERSION = "v00001"; |
| 26 /** | 29 |
| 27 * Each dependency record contains the library in which it was found, along wi
th a hash of its | 30 /** |
| 28 * structure. Any change in the hash of the target dependency will force a rec
ompile of the | 31 * Each dependency record contains the library in which it was found, name of
the unit in this |
| 29 * associated compilation unit. | 32 * library and last-modified timestamp. Any change in the timestamp of the tar
get dependency will |
| 33 * force a recompile of the associated compilation unit. |
| 30 */ | 34 */ |
| 31 public static class Dependency { | 35 public static class Dependency { |
| 32 private final URI libUri; | 36 private final URI libUri; |
| 33 private final String hash; | 37 private final String unitName; |
| 34 | 38 private final long lastModified; |
| 35 public Dependency(URI libUri, String hash) { | 39 |
| 40 public Dependency(URI libUri, String unitName, long lastModified) { |
| 36 this.libUri = libUri; | 41 this.libUri = libUri; |
| 37 this.hash = hash; | 42 this.unitName = unitName; |
| 38 } | 43 this.lastModified = lastModified; |
| 39 | 44 } |
| 40 public String getHash() { | 45 |
| 41 return hash; | 46 @Override |
| 47 public boolean equals(Object obj) { |
| 48 if (obj instanceof Dependency) { |
| 49 Dependency dep = (Dependency) obj; |
| 50 return Objects.equal(libUri, dep.libUri) && Objects.equal(unitName, dep.
unitName); |
| 51 } |
| 52 return false; |
| 53 } |
| 54 |
| 55 @Override |
| 56 public int hashCode() { |
| 57 return Objects.hashCode(libUri, unitName); |
| 42 } | 58 } |
| 43 | 59 |
| 44 public URI getLibUri() { | 60 public URI getLibUri() { |
| 45 return libUri; | 61 return libUri; |
| 46 } | 62 } |
| 47 } | 63 |
| 48 | 64 public String getUnitName() { |
| 49 /** | 65 return unitName; |
| 50 * Each source is a map from class names to its associated {@link Dependency}. | 66 } |
| 51 * | 67 |
| 52 * A special dependency entry, called a 'hole', represents a name that, if | 68 public long getLastModified() { |
| 53 * newly-defined in the library scope, will force a recompile of the unit. | 69 return lastModified; |
| 54 * This is represented by the static constant {@link Source#HOLE}. | 70 } |
| 55 */ | 71 } |
| 72 |
| 56 public static class Source { | 73 public static class Source { |
| 57 private final Map<String, Dependency> deps = new ConcurrentHashMap<String, D
ependency>(); | 74 private final Set<Dependency> deps = Sets.newHashSet(); |
| 58 private final static Dependency HOLE = new Dependency(null, null); | 75 private final Set<String> topSymbols = Sets.newHashSet(); |
| 59 | 76 private final Set<String> allSymbols = Sets.newHashSet(); |
| 60 /** | 77 private final Set<String> holes = Sets.newHashSet(); |
| 61 * Gets the node names of all dependencies for this source. | 78 private boolean shouldRecompileOnAnyTopLevelChange = false; |
| 62 */ | 79 |
| 63 public Iterable<String> getNodeNames() { | 80 /** |
| 64 return deps.keySet(); | 81 * @return the {@link Set} of {@link Dependency}s. |
| 65 } | 82 */ |
| 66 | 83 public Set<Dependency> getDeps() { |
| 67 public void putDependency(String nodeName, Dependency dep) { | 84 return deps; |
| 68 deps.put(nodeName, dep); | 85 } |
| 69 } | 86 |
| 70 | 87 /** |
| 71 public Dependency getDependency(String nodeName) { | 88 * @return the names of top-level elements, such as methods and classes. |
| 72 return deps.get(nodeName); | 89 */ |
| 73 } | 90 public Set<String> getTopSymbols() { |
| 74 | 91 return topSymbols; |
| 75 public void putHole(String nodeName) { | 92 } |
| 76 deps.put(nodeName, HOLE); | 93 |
| 77 } | 94 /** |
| 78 | 95 * @return the names of all elements in unit, such as names of local variabl
es, fields, etc. |
| 79 public boolean isHole(String nodeName) { | 96 */ |
| 80 return deps.containsKey(nodeName) && (deps.get(nodeName) == HOLE); | 97 public Set<String> getAllSymbols() { |
| 81 } | 98 return allSymbols; |
| 82 } | 99 } |
| 83 | 100 |
| 84 public static LibraryDeps fromReader(Reader reader) throws IOException { | 101 /** |
| 102 * @return the names of functions, which are invoked without qualifier. So,
declaration or |
| 103 * removing function with such name on top-level should cause recomp
iling. |
| 104 */ |
| 105 public Set<String> getHoles() { |
| 106 return holes; |
| 107 } |
| 108 |
| 109 /** |
| 110 * @return <code>true</code> if this unit should be recompiled on any change
in the set of |
| 111 * top-level symbols. Typically unit has compilation errors, which p
otentially may be |
| 112 * fixed, so we should recompile this unit. |
| 113 */ |
| 114 public boolean shouldRecompileOnAnyTopLevelChange() { |
| 115 return shouldRecompileOnAnyTopLevelChange; |
| 116 } |
| 117 |
| 118 /** |
| 119 * Adds new {@link Dependency}. |
| 120 */ |
| 121 public void addDep(Dependency dep) { |
| 122 deps.add(dep); |
| 123 } |
| 124 |
| 125 /** |
| 126 * Adds symbol to the {@link Set} of top symbols. |
| 127 */ |
| 128 public void addTopSymbol(String symbol) { |
| 129 if (!Strings.isNullOrEmpty(symbol)) { |
| 130 topSymbols.add(symbol); |
| 131 } |
| 132 } |
| 133 |
| 134 /** |
| 135 * Adds symbol to the {@link Set} of all symbols. |
| 136 */ |
| 137 public void addAllSymbol(String symbol) { |
| 138 allSymbols.add(symbol); |
| 139 } |
| 140 |
| 141 /** |
| 142 * Adds new hole for {@link #getHoles()}. |
| 143 */ |
| 144 public void addHole(String hole) { |
| 145 holes.add(hole); |
| 146 } |
| 147 } |
| 148 |
| 149 public static LibraryDeps fromReader(Reader reader) { |
| 150 try { |
| 151 return fromReaderEx(reader); |
| 152 } catch (Throwable e) { |
| 153 return null; |
| 154 } |
| 155 } |
| 156 |
| 157 private static LibraryDeps fromReaderEx(Reader reader) throws Exception { |
| 85 LibraryDeps deps = new LibraryDeps(); | 158 LibraryDeps deps = new LibraryDeps(); |
| 86 BufferedReader buf = new BufferedReader(reader); | 159 BufferedReader buf = new BufferedReader(reader); |
| 87 String srcName; | 160 // Check version. |
| 88 while (null != (srcName = buf.readLine())) { | 161 { |
| 89 Source src = new Source(); | 162 String line = buf.readLine(); |
| 90 | 163 if (!Objects.equal(line, VERSION)) { |
| 91 String line; | 164 return deps; |
| 92 while (null != (line = buf.readLine())) { | 165 } |
| 93 // Blank line: next source. | 166 } |
| 167 // Read units dependencies. |
| 168 String relPath; |
| 169 while (null != (relPath = buf.readLine())) { |
| 170 Source source = new Source(); |
| 171 // Read flags. |
| 172 source.shouldRecompileOnAnyTopLevelChange = Boolean.parseBoolean(buf.readL
ine()); |
| 173 // Read top symbols. |
| 174 { |
| 175 String line = buf.readLine(); |
| 176 Iterable<String> topSymbols = Splitter.on(' ').omitEmptyStrings().split(
line); |
| 177 Iterables.addAll(source.topSymbols, topSymbols); |
| 178 } |
| 179 // Read all symbols. |
| 180 { |
| 181 String line = buf.readLine(); |
| 182 Iterable<String> allSymbols = Splitter.on(' ').omitEmptyStrings().split(
line); |
| 183 Iterables.addAll(source.allSymbols, allSymbols); |
| 184 } |
| 185 // Read holes. |
| 186 { |
| 187 String line = buf.readLine(); |
| 188 Iterable<String> holes = Splitter.on(' ').omitEmptyStrings().split(line)
; |
| 189 Iterables.addAll(source.holes, holes); |
| 190 } |
| 191 // Read dependencies. |
| 192 while (true) { |
| 193 String line = buf.readLine(); |
| 194 // Blank line: next unit. |
| 94 if (line.length() == 0) { | 195 if (line.length() == 0) { |
| 95 break; | 196 break; |
| 96 } | 197 } |
| 97 | 198 // Parse line. |
| 98 String[] parts = line.split(" "); | 199 String[] parts = line.split(" "); |
| 99 switch (parts.length) { | 200 source.deps.add(new Dependency(new URI(parts[0]), parts[1], Long.parseLo
ng(parts[2]))); |
| 100 case 3: | 201 } |
| 101 // Full dependency. | 202 // Remember dependencies for current unit. |
| 102 try { | 203 deps.sources.put(relPath, source); |
| 103 src.deps.put(parts[0], new Dependency(new URI(parts[1]), parts[2])
); | 204 } |
| 104 } catch (URISyntaxException e) { | |
| 105 return null; | |
| 106 } | |
| 107 break; | |
| 108 case 1: | |
| 109 // Name only: hole. | |
| 110 src.deps.put(parts[0], Source.HOLE); | |
| 111 break; | |
| 112 default: | |
| 113 return null; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 deps.sources.put(srcName, src); | |
| 118 } | |
| 119 | |
| 120 return deps; | 205 return deps; |
| 121 } | 206 } |
| 122 | 207 |
| 123 private final Map<String, Source> sources = new ConcurrentHashMap<String, Sour
ce>(); | 208 private final Map<String, Source> sources = Maps.newHashMap(); |
| 124 | 209 |
| 125 public LibraryDeps() { | 210 public LibraryDeps() { |
| 126 } | 211 } |
| 127 | 212 |
| 128 public Source getSource(String sourceName) { | 213 /** |
| 129 return sources.get(sourceName); | 214 * @return the relative paths of all units with remembered dependencies. |
| 130 } | 215 */ |
| 131 | 216 public Set<String> getUnitPaths() { |
| 132 public Iterable<String> getSourceNames() { | |
| 133 return sources.keySet(); | 217 return sources.keySet(); |
| 134 } | 218 } |
| 135 | 219 |
| 136 public void setSource(String sourceName, Source source) { | 220 /** |
| 137 sources.put(sourceName, source); | 221 * @return all {@link Source} descriptions for all units in this library. |
| 138 } | 222 */ |
| 139 | 223 public Iterable<Source> getSources() { |
| 140 @Override | 224 return sources.values(); |
| 141 public String toString() { | 225 } |
| 142 try { | 226 |
| 143 StringWriter writer = new StringWriter(); | 227 /** |
| 144 write(writer); | 228 * @return the {@link Source} description of the unit with given path. |
| 145 return writer.toString(); | 229 */ |
| 146 } catch (IOException e) { | 230 public Source getSource(String relPath) { |
| 147 throw new AssertionError(); | 231 return sources.get(relPath); |
| 148 } | 232 } |
| 149 } | 233 |
| 150 | 234 /** |
| 151 public void update(DartUnit unit, DartCompilerContext context) { | 235 * Remembers {@link Dependency}s of the unit with given path. |
| 152 // Update the library deps to reflect this unit's classes. | 236 */ |
| 153 LibraryDepsVisitor.exec(unit, this); | 237 public void putSource(String relPath, Source source) { |
| 238 sources.put(relPath, source); |
| 239 } |
| 240 |
| 241 /** |
| 242 * Update the library dependencies to reflect this unit's classes. |
| 243 */ |
| 244 public void update(DartCompilerMainContext context, DartUnit unit) { |
| 245 Source source = new Source(); |
| 246 String relPath = unit.getSource().getRelativePath(); |
| 247 putSource(relPath, source); |
| 248 // Remember dependencies. |
| 249 LibraryDepsVisitor.exec(unit, source); |
| 250 // Fill Source with symbols. |
| 251 for (String name : unit.getDeclarationNames()) { |
| 252 source.addAllSymbol(name); |
| 253 } |
| 254 for (String name : unit.getTopDeclarationNames()) { |
| 255 source.addTopSymbol(name); |
| 256 } |
| 257 // Analyze errors and see if any of them should force recompilation. |
| 258 List<DartCompilationError> sourceErrors = context.getSourceErrors(unit.getSo
urce()); |
| 259 for (DartCompilationError error : sourceErrors) { |
| 260 if (error.getErrorCode().needsRecompilation()) { |
| 261 source.shouldRecompileOnAnyTopLevelChange = true; |
| 262 break; |
| 263 } |
| 264 } |
| 154 } | 265 } |
| 155 | 266 |
| 156 public void write(Writer writer) throws IOException { | 267 public void write(Writer writer) throws IOException { |
| 157 // For stability from run to run, this output needs to be sorted | 268 // Write version. |
| 158 ArrayList<String> sortedSourceNames = new ArrayList<String>(sources.size()); | 269 writer.write(VERSION); |
| 159 sortedSourceNames.addAll(sources.keySet()); | 270 writer.write('\n'); |
| 160 Collections.sort(sortedSourceNames); | 271 // Write entries. |
| 161 | 272 for (Entry<String, Source> entry : sources.entrySet()) { |
| 162 for (String srcName : sortedSourceNames) { | 273 String relPath = entry.getKey(); |
| 163 writer.write(srcName); | 274 Source source = entry.getValue(); |
| 164 writer.write('\n'); | 275 // Unit name. |
| 165 Source src = sources.get(srcName); | 276 writer.write(relPath); |
| 166 | 277 writer.write('\n'); |
| 167 // sort the types per source name | 278 // Flags. |
| 168 ArrayList<String> sortedTypes = new ArrayList<String>(src.deps.size()); | 279 writer.write(Boolean.toString(source.shouldRecompileOnAnyTopLevelChange)); |
| 169 sortedTypes.addAll(src.deps.keySet()); | 280 writer.write('\n'); |
| 170 Collections.sort(sortedTypes); | 281 // Write top symbols. |
| 171 | 282 for (String symbol : source.topSymbols) { |
| 172 for (String type : sortedTypes) { | 283 writer.write(symbol); |
| 173 writer.write(type); | 284 writer.write(' '); |
| 174 | 285 } |
| 175 Dependency dep = src.getDependency(type); | 286 writer.write('\n'); |
| 176 if (dep != Source.HOLE) { | 287 // Write all symbols. |
| 177 writer.write(' '); | 288 for (String symbol : source.allSymbols) { |
| 178 writer.write(dep.libUri.toString()); | 289 writer.write(symbol); |
| 179 writer.write(' '); | 290 writer.write(' '); |
| 180 writer.write(dep.hash); | 291 } |
| 181 } | 292 writer.write('\n'); |
| 182 | 293 // Write holes. |
| 294 for (String hole : source.holes) { |
| 295 writer.write(hole); |
| 296 writer.write(' '); |
| 297 } |
| 298 writer.write('\n'); |
| 299 // Write dependencies. |
| 300 for (Dependency dep : source.deps) { |
| 301 writer.write(dep.libUri.toString()); |
| 302 writer.write(' '); |
| 303 writer.write(dep.unitName); |
| 304 writer.write(' '); |
| 305 writer.write(Long.toString(dep.lastModified)); |
| 183 writer.write('\n'); | 306 writer.write('\n'); |
| 184 } | 307 } |
| 185 | 308 // Empty line after each unit. |
| 186 writer.write('\n'); | 309 writer.write('\n'); |
| 187 } | 310 } |
| 188 } | 311 } |
| 189 } | 312 } |
| OLD | NEW |