| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 | 4 |
| 5 import "dart:async"; | 5 import "dart:async"; |
| 6 import "dart:convert"; | 6 import "dart:convert"; |
| 7 import "dart:io"; | 7 import "dart:io"; |
| 8 import "dart:isolate"; | 8 import "dart:isolate"; |
| 9 import "dart:mirrors"; | 9 import "dart:mirrors"; |
| 10 | 10 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 } | 65 } |
| 66 return filePath; | 66 return filePath; |
| 67 } | 67 } |
| 68 if (import.startsWith(PACKAGE_PREFIX)) { | 68 if (import.startsWith(PACKAGE_PREFIX)) { |
| 69 if (_env["pkgRoot"] == null) { | 69 if (_env["pkgRoot"] == null) { |
| 70 // No package-root given, do not resolve package: URIs. | 70 // No package-root given, do not resolve package: URIs. |
| 71 return null; | 71 return null; |
| 72 } | 72 } |
| 73 var filePath = | 73 var filePath = |
| 74 "${_env["pkgRoot"]}" | 74 "${_env["pkgRoot"]}" |
| 75 "/${import.substring(PACKAGE_PREFIX.length, import.length)}"; | 75 "/${import.substring(PACKAGE_PREFIX.length, import.length)}"; |
| 76 return filePath; | 76 return filePath; |
| 77 } | 77 } |
| 78 if (import.startsWith(FILE_PREFIX)) { | 78 if (import.startsWith(FILE_PREFIX)) { |
| 79 var filePath = fromUri(Uri.parse(import)); | 79 var filePath = fromUri(Uri.parse(import)); |
| 80 return filePath; | 80 return filePath; |
| 81 } | 81 } |
| 82 if (import.startsWith(HTTP_PREFIX)) { | 82 if (import.startsWith(HTTP_PREFIX)) { |
| 83 return import; | 83 return import; |
| 84 } | 84 } |
| 85 // We cannot deal with anything else. | 85 // We cannot deal with anything else. |
| 86 failed.add(import); | 86 failed.add(import); |
| 87 return null; | 87 return null; |
| 88 } | 88 } |
| 89 } | 89 } |
| 90 | 90 |
| 91 /// Converts the given hitmap to lcov format and appends the result to | 91 /// Converts the given hitmap to lcov format and appends the result to |
| 92 /// env.output. | 92 /// env.output. |
| 93 /// | 93 /// |
| 94 /// Returns a [Future] that completes as soon as all map entries have been | 94 /// Returns a [Future] that completes as soon as all map entries have been |
| 95 /// emitted. | 95 /// emitted. |
| 96 Future lcov(Map hitmap) { | 96 Future lcov(Map hitmap) { |
| 97 var emitOne = (key) { | 97 var emitOne = (key) { |
| 98 var v = hitmap[key]; | 98 var v = hitmap[key]; |
| 99 StringBuffer entry = new StringBuffer(); | 99 StringBuffer entry = new StringBuffer(); |
| 100 entry.write("SF:${key}\n"); | 100 entry.write("SF:${key}\n"); |
| 101 v.keys.toList() | 101 v.keys.toList() |
| 102 ..sort() | 102 ..sort() |
| 103 ..forEach((k) { | 103 ..forEach((k) { |
| 104 entry.write("DA:${k},${v[k]}\n"); | 104 entry.write("DA:${k},${v[k]}\n"); |
| 105 }); | 105 }); |
| 106 entry.write("end_of_record\n"); | 106 entry.write("end_of_record\n"); |
| 107 env.output.write(entry.toString()); | 107 env.output.write(entry.toString()); |
| 108 return new Future.value(null); | 108 return new Future.value(null); |
| 109 }; | 109 }; |
| 110 | 110 |
| 111 return Future.forEach(hitmap.keys, emitOne); | 111 return Future.forEach(hitmap.keys, emitOne); |
| 112 } | 112 } |
| 113 | 113 |
| 114 /// Converts the given hitmap to a pretty-print format and appends the result | 114 /// Converts the given hitmap to a pretty-print format and appends the result |
| 115 /// to env.output. | 115 /// to env.output. |
| 116 /// | 116 /// |
| 117 /// Returns a [Future] that completes as soon as all map entries have been | 117 /// Returns a [Future] that completes as soon as all map entries have been |
| 118 /// emitted. | 118 /// emitted. |
| 119 Future prettyPrint(Map hitMap, List failedLoads) { | 119 Future prettyPrint(Map hitMap, List failedLoads) { |
| 120 var emitOne = (key) { | 120 var emitOne = (key) { |
| 121 var v = hitMap[key]; | 121 var v = hitMap[key]; |
| 122 var c = new Completer(); | 122 var c = new Completer(); |
| 123 loadResource(key).then((lines) { | 123 loadResource(key).then((lines) { |
| 124 if (lines == null) { | 124 if (lines == null) { |
| 125 failedLoads.add(key); | 125 failedLoads.add(key); |
| 126 c.complete(); | 126 c.complete(); |
| 127 return; | 127 return; |
| 128 } | 128 } |
| 129 env.output.write("${key}\n"); | 129 env.output.write("${key}\n"); |
| 130 for (var line = 1; line <= lines.length; line++) { | 130 for (var line = 1; line <= lines.length; line++) { |
| 131 String prefix = " "; | 131 String prefix = " "; |
| 132 if (v.containsKey(line)) { | 132 if (v.containsKey(line)) { |
| 133 prefix = v[line].toString(); | 133 prefix = v[line].toString(); |
| 134 StringBuffer b = new StringBuffer(); | 134 StringBuffer b = new StringBuffer(); |
| 135 for (int i = prefix.length; i < 7; i++) { | 135 for (int i = prefix.length; i < 7; i++) { |
| 136 b.write(" "); | 136 b.write(" "); |
| 137 } | 137 } |
| 138 b.write(prefix); | 138 b.write(prefix); |
| 139 prefix = b.toString(); | 139 prefix = b.toString(); |
| 140 } | 140 } |
| 141 env.output.write("${prefix}|${lines[line-1]}\n"); | 141 env.output.write("${prefix}|${lines[line-1]}\n"); |
| 142 } | 142 } |
| 143 c.complete(); | 143 c.complete(); |
| 144 }); | 144 }); |
| 145 return c.future; | 145 return c.future; |
| 146 }; | 146 }; |
| 147 | 147 |
| 148 return Future.forEach(hitMap.keys, emitOne); | 148 return Future.forEach(hitMap.keys, emitOne); |
| 149 } | 149 } |
| 150 | 150 |
| 151 /// Load an import resource and return a [Future] with a [List] of its lines. | 151 /// Load an import resource and return a [Future] with a [List] of its lines. |
| 152 /// Returns [null] instead of a list if the resource could not be loaded. | 152 /// Returns [null] instead of a list if the resource could not be loaded. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 | 184 |
| 185 addToMap(source, line, count) { | 185 addToMap(source, line, count) { |
| 186 if (!hitMap[source].containsKey(line)) { | 186 if (!hitMap[source].containsKey(line)) { |
| 187 hitMap[source][line] = 0; | 187 hitMap[source][line] = 0; |
| 188 } | 188 } |
| 189 hitMap[source][line] += count; | 189 hitMap[source][line] += count; |
| 190 } | 190 } |
| 191 | 191 |
| 192 JSON.decode(rawJson).forEach((Map e) { | 192 JSON.decode(rawJson).forEach((Map e) { |
| 193 String source = resolver.resolve(e["source"]); | 193 String source = resolver.resolve(e["source"]); |
| 194 if (source == null) { | 194 if (source == null) { |
| 195 // Couldnt resolve import, so skip this entry. | 195 // Couldnt resolve import, so skip this entry. |
| 196 return; | 196 return; |
| 197 } | 197 } |
| 198 if (!hitMap.containsKey(source)) { | 198 if (!hitMap.containsKey(source)) { |
| 199 hitMap[source] = {}; | 199 hitMap[source] = {}; |
| 200 } | 200 } |
| 201 var hits = e["hits"]; | 201 var hits = e["hits"]; |
| 202 // hits is a flat array of the following format: | 202 // hits is a flat array of the following format: |
| 203 // [ <line|linerange>, <hitcount>,...] | 203 // [ <line|linerange>, <hitcount>,...] |
| 204 // line: number. | 204 // line: number. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 226 /// Merges [newMap] into [result]. | 226 /// Merges [newMap] into [result]. |
| 227 mergeHitmaps(Map newMap, Map result) { | 227 mergeHitmaps(Map newMap, Map result) { |
| 228 newMap.forEach((String file, Map v) { | 228 newMap.forEach((String file, Map v) { |
| 229 if (result.containsKey(file)) { | 229 if (result.containsKey(file)) { |
| 230 v.forEach((int line, int cnt) { | 230 v.forEach((int line, int cnt) { |
| 231 if (result[file][line] == null) { | 231 if (result[file][line] == null) { |
| 232 result[file][line] = cnt; | 232 result[file][line] = cnt; |
| 233 } else { | 233 } else { |
| 234 result[file][line] += cnt; | 234 result[file][line] += cnt; |
| 235 } | 235 } |
| 236 }); | 236 }); |
| 237 } else { | 237 } else { |
| 238 result[file] = v; | 238 result[file] = v; |
| 239 } | 239 } |
| 240 }); | 240 }); |
| 241 } | 241 } |
| 242 | 242 |
| 243 /// Given an absolute path absPath, this function returns a [List] of files | 243 /// Given an absolute path absPath, this function returns a [List] of files |
| 244 /// are contained by it if it is a directory, or a [List] containing the file if | 244 /// are contained by it if it is a directory, or a [List] containing the file if |
| 245 /// it is a file. | 245 /// it is a file. |
| 246 List filesToProcess(String absPath) { | 246 List filesToProcess(String absPath) { |
| 247 var filePattern = new RegExp(r"^dart-cov-\d+-\d+.json$"); |
| 247 if (FileSystemEntity.isDirectorySync(absPath)) { | 248 if (FileSystemEntity.isDirectorySync(absPath)) { |
| 248 Directory d = new Directory(absPath); | 249 return new Directory(absPath).listSync(recursive: true) |
| 249 List files = []; | 250 .where((entity) => entity is File && |
| 250 d.listSync(recursive: true).forEach((FileSystemEntity entity) { | 251 filePattern.hasMatch(basename(entity.path))) |
| 251 if (entity is File) { | 252 .toList(); |
| 252 files.add(entity as File); | 253 } |
| 253 } | 254 |
| 254 }); | 255 return [new File(absPath)]; |
| 255 return files; | |
| 256 } else if (FileSystemEntity.isFileSync(absPath)) { | |
| 257 return [ new File(absPath) ]; | |
| 258 } | |
| 259 } | 256 } |
| 260 | 257 |
| 261 worker() { | 258 worker() { |
| 262 final start = new DateTime.now().millisecondsSinceEpoch; | 259 final start = new DateTime.now().millisecondsSinceEpoch; |
| 263 String me = currentMirrorSystem().isolate.debugName; | 260 String me = currentMirrorSystem().isolate.debugName; |
| 264 | 261 |
| 265 port.receive((Message message, reply) { | 262 port.receive((Message message, reply) { |
| 266 if (message.type == Message.SHUTDOWN) { | 263 if (message.type == Message.SHUTDOWN) { |
| 267 port.close(); | 264 port.close(); |
| 268 } | 265 } |
| 269 | 266 |
| 270 if (message.type == Message.WORK) { | 267 if (message.type == Message.WORK) { |
| 271 var env = message.payload[0]; | 268 var env = message.payload[0]; |
| 272 List files = message.payload[1]; | 269 List files = message.payload[1]; |
| 273 Resolver resolver = new Resolver(env); | 270 Resolver resolver = new Resolver(env); |
| 274 var workerHitmap = {}; | 271 var workerHitmap = {}; |
| 275 files.forEach((File fileEntry) { | 272 files.forEach((File fileEntry) { |
| 276 // Read file sync, as it only contains 1 object. | 273 // Read file sync, as it only contains 1 object. |
| 277 String contents = fileEntry.readAsStringSync(); | 274 String contents = fileEntry.readAsStringSync(); |
| 278 if (contents.length > 0) { | 275 if (contents.length > 0) { |
| 279 mergeHitmaps(createHitmap(contents, resolver), workerHitmap); | 276 mergeHitmaps(createHitmap(contents, resolver), workerHitmap); |
| 280 } | 277 } |
| 281 }); | 278 }); |
| 282 if (env["verbose"]) { | 279 if (env["verbose"]) { |
| 283 final end = new DateTime.now().millisecondsSinceEpoch; | 280 final end = new DateTime.now().millisecondsSinceEpoch; |
| 284 print("worker[${me}]: Finished processing files. " | 281 print("worker[${me}]: Finished processing files. " |
| 285 "Took ${end - start} ms."); | 282 "Took ${end - start} ms."); |
| 286 } | 283 } |
| 287 reply.send(new Message(Message.RESULT, [workerHitmap, resolver.failed])); | 284 reply.send(new Message(Message.RESULT, [workerHitmap, resolver.failed])); |
| 288 } | 285 } |
| 289 | 286 |
| 290 }); | 287 }); |
| 291 } | 288 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 319 if (env.verbose) { | 316 if (env.verbose) { |
| 320 print("Environment:"); | 317 print("Environment:"); |
| 321 print(" # files: ${files.length}"); | 318 print(" # files: ${files.length}"); |
| 322 print(" # workers: ${env.workers}"); | 319 print(" # workers: ${env.workers}"); |
| 323 print(" sdk-root: ${env.sdkRoot}"); | 320 print(" sdk-root: ${env.sdkRoot}"); |
| 324 print(" package-root: ${env.pkgRoot}"); | 321 print(" package-root: ${env.pkgRoot}"); |
| 325 } | 322 } |
| 326 | 323 |
| 327 port.receive((Message message, reply) { | 324 port.receive((Message message, reply) { |
| 328 if (message.type == Message.RESULT) { | 325 if (message.type == Message.RESULT) { |
| 329 mergeHitmaps(message.payload[0], globalHitmap); | 326 mergeHitmaps(message.payload[0], globalHitmap); |
| 330 failedResolves.addAll(message.payload[1]); | 327 failedResolves.addAll(message.payload[1]); |
| 331 doneCnt++; | 328 doneCnt++; |
| 332 } | 329 } |
| 333 | 330 |
| 334 // All workers are done. Process the data. | 331 // All workers are done. Process the data. |
| 335 if (doneCnt == env.workers) { | 332 if (doneCnt == env.workers) { |
| 336 workerPorts.forEach((p) => p.send(new Message(Message.SHUTDOWN, null))); | 333 workerPorts.forEach((p) => p.send(new Message(Message.SHUTDOWN, null))); |
| 337 if (env.verbose) { | 334 if (env.verbose) { |
| 338 final end = new DateTime.now().millisecondsSinceEpoch; | 335 final end = new DateTime.now().millisecondsSinceEpoch; |
| 339 print("Done creating a global hitmap. Took ${end - start} ms."); | 336 print("Done creating a global hitmap. Took ${end - start} ms."); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 } | 493 } |
| 497 | 494 |
| 498 try { | 495 try { |
| 499 env.workers = int.parse("${args["workers"]}"); | 496 env.workers = int.parse("${args["workers"]}"); |
| 500 } catch (e) { | 497 } catch (e) { |
| 501 fail("Invalid worker count: $e"); | 498 fail("Invalid worker count: $e"); |
| 502 } | 499 } |
| 503 | 500 |
| 504 env.verbose = args["verbose"]; | 501 env.verbose = args["verbose"]; |
| 505 } | 502 } |
| OLD | NEW |