| 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:isolate'; | 7 import 'dart:isolate'; |
| 8 | 8 |
| 9 import 'package:barback/barback.dart'; | 9 import 'package:barback/barback.dart'; |
| 10 import 'package:source_span/source_span.dart'; | 10 import 'package:source_span/source_span.dart'; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 /// | 42 /// |
| 43 /// This doesn't actually instantiate any transformers, since a | 43 /// This doesn't actually instantiate any transformers, since a |
| 44 /// [TransformerId] doesn't define the transformers' configuration. The | 44 /// [TransformerId] doesn't define the transformers' configuration. The |
| 45 /// transformers can be constructed using [create]. | 45 /// transformers can be constructed using [create]. |
| 46 /// | 46 /// |
| 47 /// If [snapshot] is passed, the isolate will be loaded from that path if it | 47 /// If [snapshot] is passed, the isolate will be loaded from that path if it |
| 48 /// exists. Otherwise, a snapshot of the isolate's code will be saved to that | 48 /// exists. Otherwise, a snapshot of the isolate's code will be saved to that |
| 49 /// path once the isolate is loaded. | 49 /// path once the isolate is loaded. |
| 50 static Future<TransformerIsolate> spawn(AssetEnvironment environment, | 50 static Future<TransformerIsolate> spawn(AssetEnvironment environment, |
| 51 BarbackServer transformerServer, List<TransformerId> ids, | 51 BarbackServer transformerServer, List<TransformerId> ids, |
| 52 {String snapshot}) { | 52 {String snapshot}) async { |
| 53 return mapFromIterableAsync(ids, value: (id) { | 53 var idsToAssetIds = <TransformerId, AssetId>{}; |
| 54 return id.getAssetId(environment.barback); | 54 var idsToUrls = <TransformerId, Uri>{}; |
| 55 }).then((idsToAssetIds) { | 55 await Future.wait(ids.map((id) async { |
| 56 var baseUrl = transformerServer.url; | 56 var assetId = await id.getAssetId(environment.barback); |
| 57 var idsToUrls = mapMap(idsToAssetIds, value: (id, assetId) { | 57 idsToAssetIds[id] = assetId; |
| 58 var path = assetId.path.replaceFirst('lib/', ''); | |
| 59 return Uri.parse('package:${id.package}/$path'); | |
| 60 }); | |
| 61 | 58 |
| 62 var code = new StringBuffer(); | 59 var path = assetId.path.replaceFirst('lib/', ''); |
| 63 code.writeln("import 'dart:isolate';"); | 60 idsToUrls[id] = Uri.parse('package:${id.package}/$path'); |
| 61 })); |
| 64 | 62 |
| 65 for (var url in idsToUrls.values) { | 63 var code = new StringBuffer(); |
| 66 code.writeln("import '$url';"); | 64 code.writeln("import 'dart:isolate';"); |
| 67 } | |
| 68 | 65 |
| 69 code.writeln("import r'package:\$pub/transformer_isolate.dart';"); | 66 for (var url in idsToUrls.values) { |
| 70 code.writeln( | 67 code.writeln("import '$url';"); |
| 71 "void main(_, SendPort replyTo) => loadTransformers(replyTo);"); | 68 } |
| 72 | 69 |
| 73 log.fine("Loading transformers from $ids"); | 70 code.writeln("import r'package:\$pub/transformer_isolate.dart';"); |
| 71 code.writeln( |
| 72 "void main(_, SendPort replyTo) => loadTransformers(replyTo);"); |
| 74 | 73 |
| 75 var port = new ReceivePort(); | 74 log.fine("Loading transformers from $ids"); |
| 76 return dart.runInIsolate(code.toString(), port.sendPort, | |
| 77 packageRoot: baseUrl.resolve('packages'), | |
| 78 snapshot: snapshot) | |
| 79 .then((_) => port.first) | |
| 80 .then((sendPort) { | |
| 81 return new TransformerIsolate._(sendPort, environment.mode, idsToUrls); | |
| 82 }).catchError((error, stackTrace) { | |
| 83 if (error is! CrossIsolateException) throw error; | |
| 84 if (error.type != 'IsolateSpawnException') throw error; | |
| 85 | 75 |
| 86 // TODO(nweiz): don't parse this as a string once issues 12617 and 12689 | 76 var port = new ReceivePort(); |
| 87 // are fixed. | 77 try { |
| 88 var firstErrorLine = error.message.split('\n')[1]; | 78 await dart.runInIsolate(code.toString(), port.sendPort, |
| 79 packageRoot: transformerServer.url.resolve('packages'), |
| 80 snapshot: snapshot); |
| 81 return new TransformerIsolate._( |
| 82 await port.first, environment.mode, idsToUrls); |
| 83 } on CrossIsolateException catch (error, stackTrace) { |
| 84 if (error.type != 'IsolateSpawnException') throw error; |
| 89 | 85 |
| 90 // The isolate error message contains the fully expanded path, not the | 86 // TODO(nweiz): don't parse this as a string once issues 12617 and 12689 |
| 91 // "package:" URI, so we have to be liberal in what we look for in the | 87 // are fixed. |
| 92 // error message. | 88 var firstErrorLine = error.message.split('\n')[1]; |
| 93 var missingTransformer = idsToUrls.keys.firstWhere((id) => | |
| 94 firstErrorLine.startsWith('Could not import "${idsToUrls[id]}"'), | |
| 95 orElse: () => throw error); | |
| 96 var packageUri = idToPackageUri(idsToAssetIds[missingTransformer]); | |
| 97 | 89 |
| 98 // If there was an IsolateSpawnException and the import that actually | 90 // The isolate error message contains the fully expanded path, not the |
| 99 // failed was the one we were loading transformers from, throw an | 91 // "package:" URI, so we have to be liberal in what we look for in the |
| 100 // application exception with a more user-friendly message. | 92 // error message. |
| 101 fail('Transformer library "$packageUri" not found.', | 93 var missingTransformer = idsToUrls.keys.firstWhere((id) => |
| 102 error, stackTrace); | 94 firstErrorLine.startsWith('Could not import "${idsToUrls[id]}"'), |
| 103 }); | 95 orElse: () => throw error); |
| 104 }); | 96 var packageUri = idToPackageUri(idsToAssetIds[missingTransformer]); |
| 97 |
| 98 // If there was an IsolateSpawnException and the import that actually |
| 99 // failed was the one we were loading transformers from, throw an |
| 100 // application exception with a more user-friendly message. |
| 101 fail('Transformer library "$packageUri" not found.', |
| 102 error, stackTrace); |
| 103 return null; |
| 104 } |
| 105 } | 105 } |
| 106 | 106 |
| 107 TransformerIsolate._(this._port, this._mode, this._idsToUrls); | 107 TransformerIsolate._(this._port, this._mode, this._idsToUrls); |
| 108 | 108 |
| 109 /// Instantiate the transformers in the [config.id] with | 109 /// Instantiate the transformers in the [config.id] with |
| 110 /// [config.configuration]. | 110 /// [config.configuration]. |
| 111 /// | 111 /// |
| 112 /// If there are no transformers defined in the given library, this will | 112 /// If there are no transformers defined in the given library, this will |
| 113 /// return an empty set. | 113 /// return an empty set. |
| 114 Future<Set<Transformer>> create(TransformerConfig config) { | 114 Future<Set<Transformer>> create(TransformerConfig config) async { |
| 115 return call(_port, { | 115 try { |
| 116 'library': _idsToUrls[config.id].toString(), | 116 var transformers = (await call/*<List>*/(_port, { |
| 117 'mode': _mode.name, | 117 'library': _idsToUrls[config.id].toString(), |
| 118 'configuration': JSON.encode(config.configuration) | 118 'mode': _mode.name, |
| 119 }).then((transformers) { | 119 'configuration': JSON.encode(config.configuration) |
| 120 transformers = transformers.map( | 120 })) |
| 121 (transformer) => deserializeTransformerLike(transformer, config)) | 121 .map((transformer) => deserializeTransformerLike(transformer, config)) |
| 122 .toSet(); | 122 .toSet(); |
| 123 log.fine("Transformers from $config: $transformers"); | 123 log.fine("Transformers from $config: $transformers"); |
| 124 return transformers; | 124 return transformers; |
| 125 }).catchError((error, stackTrace) { | 125 } catch (error) { |
| 126 throw new TransformerLoadError(error, config.span); | 126 throw new TransformerLoadError(error, config.span); |
| 127 }); | 127 } |
| 128 } | 128 } |
| 129 } | 129 } |
| 130 | 130 |
| 131 /// An error thrown when a transformer fails to load. | 131 /// An error thrown when a transformer fails to load. |
| 132 class TransformerLoadError extends SourceSpanException | 132 class TransformerLoadError extends SourceSpanException |
| 133 implements WrappedException { | 133 implements WrappedException { |
| 134 final CrossIsolateException innerError; | 134 final CrossIsolateException innerError; |
| 135 Chain get innerChain => innerError.stackTrace; | 135 Chain get innerChain => innerError.stackTrace; |
| 136 | 136 |
| 137 TransformerLoadError(CrossIsolateException error, SourceSpan span) | 137 TransformerLoadError(CrossIsolateException error, SourceSpan span) |
| 138 : innerError = error, | 138 : innerError = error, |
| 139 super("Error loading transformer: ${error.message}", span); | 139 super("Error loading transformer: ${error.message}", span); |
| 140 } | 140 } |
| OLD | NEW |