| Index: sdk/lib/_internal/pub/lib/src/barback/asset_environment.dart
|
| diff --git a/sdk/lib/_internal/pub/lib/src/barback/asset_environment.dart b/sdk/lib/_internal/pub/lib/src/barback/asset_environment.dart
|
| index e9d50aa2ee85705ac41abd4d7551d2868b038669..04acfa4439a89876a2478c50ccc1ad0c93802209 100644
|
| --- a/sdk/lib/_internal/pub/lib/src/barback/asset_environment.dart
|
| +++ b/sdk/lib/_internal/pub/lib/src/barback/asset_environment.dart
|
| @@ -19,6 +19,7 @@ import '../package.dart';
|
| import '../package_graph.dart';
|
| import '../sdk.dart' as sdk;
|
| import '../source/cached.dart';
|
| +import '../utils.dart';
|
| import 'admin_server.dart';
|
| import 'barback_server.dart';
|
| import 'dart_forwarding_transformer.dart';
|
| @@ -369,7 +370,10 @@ class AssetEnvironment {
|
| // infrastructure to share code with pub proper. We provide it only during
|
| // the initial transformer loading process.
|
| var dartPath = assetPath('dart');
|
| - var pubSources = listDir(dartPath, recursive: true).map((library) {
|
| + var pubSources = listDir(dartPath, recursive: true)
|
| + // Don't include directories.
|
| + .where((file) => path.extension(file) == ".dart")
|
| + .map((library) {
|
| var idPath = path.join('lib', path.relative(library, from: dartPath));
|
| return new AssetId('\$pub', path.toUri(idPath).toString());
|
| });
|
| @@ -391,59 +395,48 @@ class AssetEnvironment {
|
| return BarbackServer.bind(this, _hostname, 0, null).then((server) {
|
| transformerServer = server;
|
|
|
| - return log.progress("Loading source assets", () {
|
| - barback.updateSources(pubSources);
|
| - barback.updateSources(sdkSources);
|
| - return _provideSources();
|
| + var errorStream = barback.errors.map((error) {
|
| + // Even most normally non-fatal barback errors should take down pub if
|
| + // they happen during the initial load process.
|
| + if (error is! AssetLoadException) throw error;
|
| +
|
| + log.error(log.red(error.message));
|
| + log.fine(error.stackTrace.terse);
|
| });
|
| +
|
| + return _withStreamErrors(() {
|
| + return log.progress("Loading source assets", () {
|
| + barback.updateSources(pubSources);
|
| + barback.updateSources(sdkSources);
|
| + return _provideSources();
|
| + });
|
| + }, [errorStream, barback.results]);
|
| }).then((_) {
|
| log.fine("Provided sources.");
|
| var completer = new Completer();
|
|
|
| - // If any errors get emitted either by barback or by the transformer
|
| - // server, including non-programmatic barback errors, they should take
|
| - // down the whole program.
|
| - var subscriptions = [
|
| - barback.errors.listen((error) {
|
| - if (error is TransformerException) {
|
| - var message = error.error.toString();
|
| - if (error.stackTrace != null) {
|
| - message += "\n" + error.stackTrace.terse.toString();
|
| - }
|
| -
|
| - _log(new LogEntry(error.transform, error.transform.primaryId,
|
| - LogLevel.ERROR, message, null));
|
| - } else if (!completer.isCompleted) {
|
| - completer.completeError(error, new Chain.current());
|
| - }
|
| - }),
|
| - barback.results.listen((_) {},
|
| - onError: (error, stackTrace) {
|
| - if (completer.isCompleted) return;
|
| - completer.completeError(error, stackTrace);
|
| - }),
|
| - transformerServer.results.listen((_) {}, onError: (error, stackTrace) {
|
| - if (completer.isCompleted) return;
|
| - completer.completeError(error, stackTrace);
|
| - })
|
| - ];
|
| -
|
| - loadAllTransformers(this, transformerServer).then((_) {
|
| - log.fine("Loaded transformers.");
|
| - return transformerServer.close();
|
| - }).then((_) {
|
| - if (!completer.isCompleted) completer.complete();
|
| - }).catchError((error, stackTrace) {
|
| - if (!completer.isCompleted) {
|
| - completer.completeError(error, stackTrace);
|
| - }
|
| - });
|
| + var errorStream = barback.errors.map((error) {
|
| + // Now that we're loading transformers, errors they log shouldn't be
|
| + // fatal, since we're starting to run them on real user assets which may
|
| + // have e.g. syntax errors. If an error would cause a transformer to
|
| + // fail to load, the load failure will cause us to exit.
|
| + if (error is! TransformerException) throw error;
|
|
|
| - return completer.future.whenComplete(() {
|
| - for (var subscription in subscriptions) {
|
| - subscription.cancel();
|
| + var message = error.error.toString();
|
| + if (error.stackTrace != null) {
|
| + message += "\n" + error.stackTrace.terse.toString();
|
| }
|
| +
|
| + _log(new LogEntry(error.transform, error.transform.primaryId,
|
| + LogLevel.ERROR, message, null));
|
| });
|
| +
|
| + return _withStreamErrors(() {
|
| + return loadAllTransformers(this, transformerServer).then((_) {
|
| + log.fine("Loaded transformers.");
|
| + return transformerServer.close();
|
| + });
|
| + }, [errorStream, barback.results, transformerServer.results]);
|
| }).then((_) => barback.removeSources(pubSources));
|
| }
|
|
|
| @@ -600,6 +593,31 @@ class AssetEnvironment {
|
|
|
| return watcher.ready.then((_) => subscription);
|
| }
|
| +
|
| + /// Returns the result of [futureCallback] unless any stream in [streams]
|
| + /// emits an error before it's done.
|
| + ///
|
| + /// If a stream does emit an error, that error is thrown instead.
|
| + /// [futureCallback] is a callback rather than a plain future to ensure that
|
| + /// [streams] are listened to before any code that might cause an error starts
|
| + /// running.
|
| + Future _withStreamErrors(Future futureCallback(), List<Stream> streams) {
|
| + var completer = new Completer.sync();
|
| + var subscriptions = streams.map((stream) =>
|
| + stream.listen((_) {}, onError: completer.complete)).toList();
|
| +
|
| + syncFuture(futureCallback).then((_) {
|
| + if (!completer.isCompleted) completer.complete();
|
| + }).catchError((error, stackTrace) {
|
| + if (!completer.isCompleted) completer.completeError(error, stackTrace);
|
| + });
|
| +
|
| + return completer.future.whenComplete(() {
|
| + for (var subscription in subscriptions) {
|
| + subscription.cancel();
|
| + }
|
| + });
|
| + }
|
| }
|
|
|
| /// Log [entry] using Pub's logging infrastructure.
|
|
|