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 |