Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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:convert'; | 5 import 'dart:convert'; |
| 6 | 6 |
| 7 import 'package:analyzer/file_system/file_system.dart'; | 7 import 'package:analyzer/file_system/file_system.dart'; |
| 8 import 'package:analyzer/src/generated/engine.dart'; | 8 import 'package:analyzer/src/generated/engine.dart'; |
| 9 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
| 10 import 'package:analyzer/src/generated/utilities_collection.dart'; | 10 import 'package:analyzer/src/generated/utilities_collection.dart'; |
| 11 import 'package:analyzer/src/summary/api_signature.dart'; | |
| 11 import 'package:analyzer/src/summary/format.dart'; | 12 import 'package:analyzer/src/summary/format.dart'; |
| 12 import 'package:analyzer/src/summary/idl.dart'; | 13 import 'package:analyzer/src/summary/idl.dart'; |
| 13 import 'package:analyzer/src/summary/link.dart'; | 14 import 'package:analyzer/src/summary/link.dart'; |
| 14 import 'package:analyzer/src/summary/package_bundle_reader.dart'; | 15 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| 15 import 'package:analyzer/src/summary/summarize_elements.dart'; | 16 import 'package:analyzer/src/summary/summarize_elements.dart'; |
| 16 import 'package:analyzer/src/util/fast_uri.dart'; | 17 import 'package:analyzer/src/util/fast_uri.dart'; |
| 17 import 'package:convert/convert.dart'; | 18 import 'package:convert/convert.dart'; |
| 18 import 'package:crypto/crypto.dart'; | 19 import 'package:crypto/crypto.dart'; |
| 19 import 'package:meta/meta.dart'; | 20 import 'package:meta/meta.dart'; |
| 20 | 21 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 91 | 92 |
| 92 /** | 93 /** |
| 93 * Class that reads summaries of Bazel packages. | 94 * Class that reads summaries of Bazel packages. |
| 94 * | 95 * |
| 95 * When the client needs to produce a resolution result for a new [Source], it | 96 * When the client needs to produce a resolution result for a new [Source], it |
| 96 * should call [getLinkedPackages] to check whether there is the set of | 97 * should call [getLinkedPackages] to check whether there is the set of |
| 97 * packages to resynthesize resolution results. | 98 * packages to resynthesize resolution results. |
| 98 */ | 99 */ |
| 99 class SummaryProvider { | 100 class SummaryProvider { |
| 100 final ResourceProvider provider; | 101 final ResourceProvider provider; |
| 102 final String tempFileName; | |
| 101 final GetOutputFolder getOutputFolder; | 103 final GetOutputFolder getOutputFolder; |
| 104 final Folder linkedCacheFolder; | |
| 102 final AnalysisContext context; | 105 final AnalysisContext context; |
| 103 final PackageBundle sdkBundle; | 106 final PackageBundle sdkBundle; |
| 104 | 107 |
| 105 /** | 108 /** |
| 109 * If `true` (by default), then linking new bundles is allowed. | |
| 110 * Otherwise only using existing cached bundles can be used. | |
| 111 */ | |
| 112 final bool allowLinking; | |
| 113 | |
| 114 /** | |
| 115 * See [PackageBundleAssembler.currentMajorVersion]. | |
| 116 */ | |
| 117 final int majorVersion; | |
| 118 | |
| 119 /** | |
| 106 * Mapping from bundle paths to corresponding [Package]s. The packages in | 120 * Mapping from bundle paths to corresponding [Package]s. The packages in |
| 107 * the map were consistent with their constituent sources at the moment when | 121 * the map were consistent with their constituent sources at the moment when |
| 108 * they were put into the map. | 122 * they were put into the map. |
| 109 */ | 123 */ |
| 110 final Map<Folder, List<Package>> folderToPackagesMap = {}; | 124 final Map<Folder, List<Package>> folderToPackagesMap = {}; |
| 111 | 125 |
| 112 /** | 126 /** |
| 113 * Mapping from [Uri]s to corresponding [_LinkNode]s. | 127 * Mapping from [Uri]s to corresponding [_LinkNode]s. |
| 114 */ | 128 */ |
| 115 final Map<Uri, _LinkNode> uriToNodeMap = {}; | 129 final Map<Uri, _LinkNode> uriToNodeMap = {}; |
| 116 | 130 |
| 117 SummaryProvider(this.provider, this.getOutputFolder, AnalysisContext context) | 131 SummaryProvider( |
| 132 this.provider, | |
| 133 this.tempFileName, | |
| 134 this.getOutputFolder, | |
| 135 this.linkedCacheFolder, | |
| 136 AnalysisContext context, | |
| 137 {@visibleForTesting | |
| 138 this.allowLinking: true, | |
| 139 @visibleForTesting | |
| 140 this.majorVersion: PackageBundleAssembler.currentMajorVersion}) | |
| 118 : context = context, | 141 : context = context, |
| 119 sdkBundle = context.sourceFactory.dartSdk?.getLinkedBundle(); | 142 sdkBundle = context.sourceFactory.dartSdk?.getLinkedBundle(); |
| 120 | 143 |
| 121 /** | 144 /** |
| 122 * Return the complete list of [Package]s that are required to provide all | 145 * Return the complete list of [Package]s that are required to provide all |
| 123 * resolution results for the given [source]. | 146 * resolution results for the given [source]. |
| 124 * | 147 * |
| 125 * The same list of packages is returned for the same [Source], i.e. always | 148 * The same list of packages is returned for the same [Source], i.e. always |
| 126 * the full list, not a difference with a previous request. It is up to the | 149 * the full list, not a difference with a previous request. It is up to the |
| 127 * client to decide whether some of the returned packages should be excluded | 150 * client to decide whether some of the returned packages should be excluded |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 140 // Compute all transitive dependencies. | 163 // Compute all transitive dependencies. |
| 141 node.computeTransitiveDependencies(); | 164 node.computeTransitiveDependencies(); |
| 142 List<_LinkNode> nodes = node.transitiveDependencies.toList(); | 165 List<_LinkNode> nodes = node.transitiveDependencies.toList(); |
| 143 nodes.forEach((dependency) => dependency.computeTransitiveDependencies()); | 166 nodes.forEach((dependency) => dependency.computeTransitiveDependencies()); |
| 144 | 167 |
| 145 // Fail if any dependency cannot be resolved. | 168 // Fail if any dependency cannot be resolved. |
| 146 if (node.failed) { | 169 if (node.failed) { |
| 147 return null; | 170 return null; |
| 148 } | 171 } |
| 149 | 172 |
| 150 _link(nodes); | 173 // Read existing cached linked bundles. |
| 174 for (_LinkNode node in nodes) { | |
| 175 _readLinked(node); | |
| 176 } | |
| 177 | |
| 178 // Link new packages, if allowed. | |
| 179 if (allowLinking) { | |
| 180 _link(nodes); | |
| 181 } | |
| 151 | 182 |
| 152 // Create successfully linked packages. | 183 // Create successfully linked packages. |
| 153 return nodes | 184 return nodes |
| 154 .map((node) => node.package) | 185 .map((node) => node.package) |
| 155 .where((package) => package.linked != null) | 186 .where((package) => package.linked != null) |
| 156 .toList(); | 187 .toList(); |
| 157 } | 188 } |
| 158 | 189 |
| 159 /** | 190 /** |
| 160 * Return the [Package] that contains information about the source with | 191 * Return the [Package] that contains information about the source with |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 180 * given [source] in [context]. | 211 * given [source] in [context]. |
| 181 */ | 212 */ |
| 182 String _computeSourceHashHex(Source source) { | 213 String _computeSourceHashHex(Source source) { |
| 183 String text = context.getContents(source).data; | 214 String text = context.getContents(source).data; |
| 184 List<int> bytes = UTF8.encode(text); | 215 List<int> bytes = UTF8.encode(text); |
| 185 List<int> hashBytes = md5.convert(bytes).bytes; | 216 List<int> hashBytes = md5.convert(bytes).bytes; |
| 186 return hex.encode(hashBytes); | 217 return hex.encode(hashBytes); |
| 187 } | 218 } |
| 188 | 219 |
| 189 /** | 220 /** |
| 221 * Return the name of the file for a linked bundle, in strong or spec mode. | |
| 222 */ | |
| 223 String _getLinkedName(String hash) { | |
| 224 if (context.analysisOptions.strongMode) { | |
| 225 return 'linked_$hash.ds'; | |
| 226 } else { | |
| 227 return 'linked_spec_$hash.ds'; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 /** | |
| 190 * Return the node for the given [uri], or `null` if there is no unlinked | 232 * Return the node for the given [uri], or `null` if there is no unlinked |
| 191 * bundle that contains [uri]. | 233 * bundle that contains [uri]. |
| 192 */ | 234 */ |
| 193 _LinkNode _getLinkNodeForUri(Uri uri) { | 235 _LinkNode _getLinkNodeForUri(Uri uri) { |
| 194 return uriToNodeMap.putIfAbsent(uri, () { | 236 return uriToNodeMap.putIfAbsent(uri, () { |
| 195 Package package = getUnlinkedForUri(uri); | 237 Package package = getUnlinkedForUri(uri); |
| 196 if (package == null) { | 238 if (package == null) { |
| 197 return null; | 239 return null; |
| 198 } | 240 } |
| 199 return new _LinkNode(this, package); | 241 return new _LinkNode(this, package); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 for (_LinkNode node in nodes) { | 332 for (_LinkNode node in nodes) { |
| 291 if (!node.isReady) { | 333 if (!node.isReady) { |
| 292 PackageBundleAssembler assembler = new PackageBundleAssembler(); | 334 PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| 293 linkedLibraries.forEach((uri, linkedLibrary) { | 335 linkedLibraries.forEach((uri, linkedLibrary) { |
| 294 if (identical(uriToNode[uri], node)) { | 336 if (identical(uriToNode[uri], node)) { |
| 295 assembler.addLinkedLibrary(uri, linkedLibrary); | 337 assembler.addLinkedLibrary(uri, linkedLibrary); |
| 296 } | 338 } |
| 297 }); | 339 }); |
| 298 List<int> bytes = assembler.assemble().toBuffer(); | 340 List<int> bytes = assembler.assemble().toBuffer(); |
| 299 node.package._linked = new PackageBundle.fromBuffer(bytes); | 341 node.package._linked = new PackageBundle.fromBuffer(bytes); |
| 342 _writeLinked(node, bytes); | |
| 300 } | 343 } |
| 301 } | 344 } |
| 302 } | 345 } |
| 346 | |
| 347 /** | |
| 348 * Attempt to read the linked bundle that corresponds to the given [node] | |
| 349 * with all its transitive dependencies. | |
| 350 */ | |
| 351 void _readLinked(_LinkNode node) { | |
| 352 if (!node.isReady && node.linkedHash != null) { | |
| 353 String fileName = _getLinkedName(node.linkedHash); | |
| 354 File file = linkedCacheFolder.getChildAssumingFile(fileName); | |
| 355 // Try to read from the file system. | |
| 356 if (file.exists) { | |
| 357 try { | |
| 358 List<int> bytes = file.readAsBytesSync(); | |
| 359 node.package._linked = new PackageBundle.fromBuffer(bytes); | |
| 360 } on FileSystemException { | |
| 361 // Ignore file system exceptions. | |
| 362 } | |
| 363 } | |
| 364 } | |
| 365 } | |
| 303 | 366 |
| 304 /** | 367 /** |
| 305 * Read the unlinked [Package] from the given [file], or return `null` if the | 368 * Read the unlinked [Package] from the given [file], or return `null` if the |
| 306 * file does not exist, or it cannot be read, or is not consistent with the | 369 * file does not exist, or it cannot be read, or is not consistent with the |
| 307 * constituent sources on the file system. | 370 * constituent sources on the file system. |
| 308 */ | 371 */ |
| 309 Package _readUnlinkedPackage(File file) { | 372 Package _readUnlinkedPackage(File file) { |
| 310 try { | 373 try { |
| 311 List<int> bytes = file.readAsBytesSync(); | 374 List<int> bytes = file.readAsBytesSync(); |
| 312 PackageBundle bundle = new PackageBundle.fromBuffer(bytes); | 375 PackageBundle bundle = new PackageBundle.fromBuffer(bytes); |
| 376 // Check the major version. | |
| 377 if (bundle.majorVersion != majorVersion) { | |
| 378 return null; | |
| 379 } | |
| 313 // Check for consistency, and fail if it's not. | 380 // Check for consistency, and fail if it's not. |
| 314 if (!_isUnlinkedBundleConsistent(bundle)) { | 381 if (!_isUnlinkedBundleConsistent(bundle)) { |
| 315 return null; | 382 return null; |
| 316 } | 383 } |
| 317 // OK, use the bundle. | 384 // OK, use the bundle. |
| 318 return new Package(file, bundle); | 385 return new Package(file, bundle); |
| 319 } on FileSystemException {} | 386 } on FileSystemException {} |
| 320 return null; | 387 return null; |
| 321 } | 388 } |
| 389 | |
| 390 /** | |
| 391 * Atomically write the given [bytes] into the file in the [folder]. | |
| 392 */ | |
| 393 void _writeAtomic(Folder folder, String fileName, List<int> bytes) { | |
| 394 String filePath = folder.getChildAssumingFile(fileName).path; | |
| 395 File tempFile = folder.getChildAssumingFile(tempFileName); | |
| 396 tempFile.writeAsBytesSync(bytes); | |
| 397 tempFile.renameSync(filePath); | |
| 398 } | |
| 399 | |
| 400 /** | |
| 401 * If a new linked bundle was linked for the given [node], write the bundle | |
| 402 * into the memory cache and the file system. | |
| 403 */ | |
| 404 void _writeLinked(_LinkNode node, List<int> bytes) { | |
| 405 String hash = node.linkedHash; | |
| 406 if (hash != null) { | |
| 407 String fileName = _getLinkedName(hash); | |
| 408 // File file = linkedCacheFolder.getChildAssumingFile(fileName); | |
|
Paul Berry
2016/09/30 20:30:47
Remove commented out lines
scheglov
2016/09/30 20:38:28
Done.
| |
| 409 // manager.linkedBundleMap[file.path] = node.linked; | |
| 410 _writeAtomic(linkedCacheFolder, fileName, bytes); | |
| 411 } | |
| 412 } | |
| 322 } | 413 } |
| 323 | 414 |
| 324 /** | 415 /** |
| 325 * Information about a single [Package]. | 416 * Information about a single [Package]. |
| 326 */ | 417 */ |
| 327 class _LinkNode { | 418 class _LinkNode { |
| 328 final SummaryProvider linker; | 419 final SummaryProvider linker; |
| 329 final Package package; | 420 final Package package; |
| 330 | 421 |
| 331 bool failed = false; | 422 bool failed = false; |
| 332 Set<_LinkNode> transitiveDependencies; | 423 Set<_LinkNode> transitiveDependencies; |
| 333 | 424 |
| 334 List<_LinkNode> _dependencies; | 425 List<_LinkNode> _dependencies; |
| 426 String _linkedHash; | |
| 335 | 427 |
| 336 _LinkNode(this.linker, this.package); | 428 _LinkNode(this.linker, this.package); |
| 337 | 429 |
| 338 /** | 430 /** |
| 339 * Retrieve the dependencies of this node. | 431 * Retrieve the dependencies of this node. |
| 340 */ | 432 */ |
| 341 List<_LinkNode> get dependencies { | 433 List<_LinkNode> get dependencies { |
| 342 if (_dependencies == null) { | 434 if (_dependencies == null) { |
| 343 Set<_LinkNode> dependencies = new Set<_LinkNode>(); | 435 Set<_LinkNode> dependencies = new Set<_LinkNode>(); |
| 344 | 436 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 return _dependencies; | 470 return _dependencies; |
| 379 } | 471 } |
| 380 | 472 |
| 381 /** | 473 /** |
| 382 * Return `true` is the node is ready - has the linked bundle or failed (does | 474 * Return `true` is the node is ready - has the linked bundle or failed (does |
| 383 * not have all required dependencies). | 475 * not have all required dependencies). |
| 384 */ | 476 */ |
| 385 bool get isReady => package.linked != null || failed; | 477 bool get isReady => package.linked != null || failed; |
| 386 | 478 |
| 387 /** | 479 /** |
| 480 * Return the hash string that corresponds to this linked bundle in the | |
| 481 * context of its SDK bundle and transitive dependencies. Return `null` if | |
| 482 * the hash computation fails, because for example the full transitive | |
| 483 * dependencies cannot computed. | |
| 484 */ | |
| 485 String get linkedHash { | |
|
Paul Berry
2016/09/30 20:30:47
This method and the one below are copied almost ex
scheglov
2016/09/30 20:38:28
Yes, these two methods are similar to the ones we
| |
| 486 if (_linkedHash == null && transitiveDependencies != null && !failed) { | |
| 487 ApiSignature signature = new ApiSignature(); | |
| 488 // Add all unlinked API signatures. | |
| 489 List<String> signatures = <String>[]; | |
| 490 signatures.add(linker.sdkBundle.apiSignature); | |
| 491 transitiveDependencies | |
| 492 .map((node) => node.package.unlinked.apiSignature) | |
| 493 .forEach(signatures.add); | |
| 494 signatures.sort(); | |
| 495 signatures.forEach(signature.addString); | |
| 496 // Combine into a single hash. | |
| 497 appendDeclaredVariables(signature); | |
| 498 _linkedHash = signature.toHex(); | |
| 499 } | |
| 500 return _linkedHash; | |
| 501 } | |
| 502 | |
| 503 /** | |
| 504 * Append names and values of all referenced declared variables (even the | |
| 505 * ones without actually declared values) to the given [signature]. | |
| 506 */ | |
| 507 void appendDeclaredVariables(ApiSignature signature) { | |
| 508 Set<String> nameSet = new Set<String>(); | |
| 509 for (_LinkNode node in transitiveDependencies) { | |
| 510 for (UnlinkedUnit unit in node.package.unlinked.unlinkedUnits) { | |
| 511 for (UnlinkedImport import in unit.imports) { | |
| 512 for (UnlinkedConfiguration configuration in import.configurations) { | |
| 513 nameSet.add(configuration.name); | |
| 514 } | |
| 515 } | |
| 516 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { | |
| 517 for (UnlinkedConfiguration configuration in export.configurations) { | |
| 518 nameSet.add(configuration.name); | |
| 519 } | |
| 520 } | |
| 521 } | |
| 522 } | |
| 523 List<String> sortedNameList = nameSet.toList()..sort(); | |
| 524 signature.addInt(sortedNameList.length); | |
| 525 for (String name in sortedNameList) { | |
| 526 signature.addString(name); | |
| 527 signature.addString(linker.context.declaredVariables.get(name) ?? ''); | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 /** | |
| 388 * Compute the set of existing transitive dependencies for this node. | 532 * Compute the set of existing transitive dependencies for this node. |
| 389 * If any dependency cannot be resolved, then set [failed] to `true`. | 533 * If any dependency cannot be resolved, then set [failed] to `true`. |
| 390 * Only unlinked bundle is used, so this method can be called before linking. | 534 * Only unlinked bundle is used, so this method can be called before linking. |
| 391 */ | 535 */ |
| 392 void computeTransitiveDependencies() { | 536 void computeTransitiveDependencies() { |
| 393 if (transitiveDependencies == null) { | 537 if (transitiveDependencies == null) { |
| 394 transitiveDependencies = new Set<_LinkNode>(); | 538 transitiveDependencies = new Set<_LinkNode>(); |
| 395 | 539 |
| 396 void appendDependencies(_LinkNode node) { | 540 void appendDependencies(_LinkNode node) { |
| 397 if (transitiveDependencies.add(node)) { | 541 if (transitiveDependencies.add(node)) { |
| 398 node.dependencies.forEach(appendDependencies); | 542 node.dependencies.forEach(appendDependencies); |
| 399 } | 543 } |
| 400 } | 544 } |
| 401 | 545 |
| 402 appendDependencies(this); | 546 appendDependencies(this); |
| 403 if (transitiveDependencies.any((node) => node.failed)) { | 547 if (transitiveDependencies.any((node) => node.failed)) { |
| 404 failed = true; | 548 failed = true; |
| 405 } | 549 } |
| 406 } | 550 } |
| 407 } | 551 } |
| 408 | 552 |
| 409 @override | 553 @override |
| 410 String toString() => package.toString(); | 554 String toString() => package.toString(); |
| 411 } | 555 } |
| OLD | NEW |