| Index: sdk/lib/_internal/pub_generated/lib/src/barback/asset_environment.dart
|
| diff --git a/sdk/lib/_internal/pub_generated/lib/src/barback/asset_environment.dart b/sdk/lib/_internal/pub_generated/lib/src/barback/asset_environment.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..99f15f55c7560a3c4e45ae6f0e9d369b9d87a5e0
|
| --- /dev/null
|
| +++ b/sdk/lib/_internal/pub_generated/lib/src/barback/asset_environment.dart
|
| @@ -0,0 +1,460 @@
|
| +library pub.barback.asset_environment;
|
| +import 'dart:async';
|
| +import 'dart:io';
|
| +import 'package:barback/barback.dart';
|
| +import 'package:path/path.dart' as path;
|
| +import 'package:watcher/watcher.dart';
|
| +import '../entrypoint.dart';
|
| +import '../exceptions.dart';
|
| +import '../io.dart';
|
| +import '../log.dart' as log;
|
| +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';
|
| +import 'dart2js_transformer.dart';
|
| +import 'load_all_transformers.dart';
|
| +import 'pub_package_provider.dart';
|
| +import 'source_directory.dart';
|
| +class AssetEnvironment {
|
| + static Future<AssetEnvironment> create(Entrypoint entrypoint,
|
| + BarbackMode mode, {WatcherType watcherType, String hostname, int basePort,
|
| + Iterable<String> packages, bool useDart2JS: true}) {
|
| + if (watcherType == null) watcherType = WatcherType.NONE;
|
| + if (hostname == null) hostname = "localhost";
|
| + if (basePort == null) basePort = 0;
|
| + return entrypoint.loadPackageGraph().then((graph) {
|
| + log.fine("Loaded package graph.");
|
| + var barback = new Barback(new PubPackageProvider(graph, packages));
|
| + barback.log.listen(_log);
|
| + var environment = new AssetEnvironment._(
|
| + graph,
|
| + barback,
|
| + mode,
|
| + watcherType,
|
| + hostname,
|
| + basePort,
|
| + packages);
|
| + return environment._load(useDart2JS: useDart2JS).then((_) => environment);
|
| + });
|
| + }
|
| + AdminServer _adminServer;
|
| + final _directories = new Map<String, SourceDirectory>();
|
| + final Barback barback;
|
| + Package get rootPackage => graph.entrypoint.root;
|
| + final PackageGraph graph;
|
| + final BarbackMode mode;
|
| + final _builtInTransformers = <Transformer>[];
|
| + final WatcherType _watcherType;
|
| + final String _hostname;
|
| + final int _basePort;
|
| + final Set<String> packages;
|
| + Set<AssetId> _modifiedSources;
|
| + AssetEnvironment._(PackageGraph graph, this.barback, this.mode,
|
| + this._watcherType, this._hostname, this._basePort, Iterable<String> packages)
|
| + : graph = graph,
|
| + packages = packages == null ?
|
| + graph.packages.keys.toSet() :
|
| + packages.toSet();
|
| + Iterable<Transformer> getBuiltInTransformers(Package package) {
|
| + if (package.name != rootPackage.name) return null;
|
| + if (_builtInTransformers.isEmpty) return null;
|
| + return _builtInTransformers;
|
| + }
|
| + Future<AdminServer> startAdminServer([int port]) {
|
| + assert(_adminServer == null);
|
| + if (port == null) port = _basePort == 0 ? 0 : _basePort - 1;
|
| + return AdminServer.bind(this, _hostname, port).then((server) => _adminServer =
|
| + server);
|
| + }
|
| + Future<BarbackServer> serveDirectory(String rootDirectory) {
|
| + var directory = _directories[rootDirectory];
|
| + if (directory != null) {
|
| + return directory.server.then((server) {
|
| + log.fine('Already serving $rootDirectory on ${server.url}.');
|
| + return server;
|
| + });
|
| + }
|
| + var overlapping = _directories.keys.where(
|
| + (directory) =>
|
| + path.isWithin(directory, rootDirectory) ||
|
| + path.isWithin(rootDirectory, directory)).toList();
|
| + if (overlapping.isNotEmpty) {
|
| + return new Future.error(
|
| + new OverlappingSourceDirectoryException(overlapping));
|
| + }
|
| + var port = _basePort;
|
| + if (port != 0) {
|
| + var boundPorts =
|
| + _directories.values.map((directory) => directory.port).toSet();
|
| + while (boundPorts.contains(port)) {
|
| + port++;
|
| + }
|
| + }
|
| + var sourceDirectory =
|
| + new SourceDirectory(this, rootDirectory, _hostname, port);
|
| + _directories[rootDirectory] = sourceDirectory;
|
| + return _provideDirectorySources(
|
| + rootPackage,
|
| + rootDirectory).then((subscription) {
|
| + sourceDirectory.watchSubscription = subscription;
|
| + return sourceDirectory.serve();
|
| + });
|
| + }
|
| + Future<BarbackServer> servePackageBinDirectory(String package) {
|
| + return _provideDirectorySources(
|
| + graph.packages[package],
|
| + "bin").then(
|
| + (_) =>
|
| + BarbackServer.bind(this, _hostname, 0, package: package, rootDirectory: "bin"));
|
| + }
|
| + Future precompileExecutables(String packageName, String directory,
|
| + {Iterable<AssetId> executableIds}) {
|
| + if (executableIds == null) {
|
| + executableIds = graph.packages[packageName].executableIds;
|
| + }
|
| + log.fine("executables for $packageName: $executableIds");
|
| + if (executableIds.isEmpty) return null;
|
| + var package = graph.packages[packageName];
|
| + return servePackageBinDirectory(packageName).then((server) {
|
| + return waitAndPrintErrors(executableIds.map((id) {
|
| + var basename = path.url.basename(id.path);
|
| + var snapshotPath = path.join(directory, "$basename.snapshot");
|
| + return runProcess(
|
| + Platform.executable,
|
| + [
|
| + '--snapshot=$snapshotPath',
|
| + server.url.resolve(basename).toString()]).then((result) {
|
| + if (result.success) {
|
| + log.message("Precompiled ${_formatExecutable(id)}.");
|
| + } else {
|
| + deleteEntry(snapshotPath);
|
| + throw new ApplicationException(
|
| + log.yellow("Failed to precompile " "${_formatExecutable(id)}:\n") +
|
| + result.stderr.join('\n'));
|
| + }
|
| + });
|
| + })).whenComplete(() {
|
| + server.close();
|
| + });
|
| + });
|
| + }
|
| + String _formatExecutable(AssetId id) =>
|
| + log.bold("${id.package}:${path.basenameWithoutExtension(id.path)}");
|
| + Future<Uri> unserveDirectory(String rootDirectory) {
|
| + log.fine("Unserving $rootDirectory.");
|
| + var directory = _directories.remove(rootDirectory);
|
| + if (directory == null) return new Future.value();
|
| + return directory.server.then((server) {
|
| + var url = server.url;
|
| + return directory.close().then((_) {
|
| + _removeDirectorySources(rootDirectory);
|
| + return url;
|
| + });
|
| + });
|
| + }
|
| + String getSourceDirectoryContaining(String assetPath) =>
|
| + _directories.values.firstWhere(
|
| + (dir) => path.isWithin(dir.directory, assetPath)).directory;
|
| + Future<List<Uri>> getUrlsForAssetPath(String assetPath) {
|
| + return _lookUpPathInServerRoot(assetPath).then((urls) {
|
| + if (urls.isNotEmpty) return urls;
|
| + return _lookUpPathInPackagesDirectory(assetPath);
|
| + }).then((urls) {
|
| + if (urls.isNotEmpty) return urls;
|
| + return _lookUpPathInDependency(assetPath);
|
| + });
|
| + }
|
| + Future<List<Uri>> _lookUpPathInServerRoot(String assetPath) {
|
| + return Future.wait(
|
| + _directories.values.where(
|
| + (dir) => path.isWithin(dir.directory, assetPath)).map((dir) {
|
| + var relativePath = path.relative(assetPath, from: dir.directory);
|
| + return dir.server.then(
|
| + (server) => server.url.resolveUri(path.toUri(relativePath)));
|
| + }));
|
| + }
|
| + Future<List<Uri>> _lookUpPathInPackagesDirectory(String assetPath) {
|
| + var components = path.split(path.relative(assetPath));
|
| + if (components.first != "packages") return new Future.value([]);
|
| + if (!packages.contains(components[1])) return new Future.value([]);
|
| + return Future.wait(_directories.values.map((dir) {
|
| + return dir.server.then(
|
| + (server) => server.url.resolveUri(path.toUri(assetPath)));
|
| + }));
|
| + }
|
| + Future<List<Uri>> _lookUpPathInDependency(String assetPath) {
|
| + for (var packageName in packages) {
|
| + var package = graph.packages[packageName];
|
| + var libDir = path.join(package.dir, 'lib');
|
| + var assetDir = path.join(package.dir, 'asset');
|
| + var uri;
|
| + if (path.isWithin(libDir, assetPath)) {
|
| + uri = path.toUri(
|
| + path.join('packages', package.name, path.relative(assetPath, from: libDir)));
|
| + } else if (path.isWithin(assetDir, assetPath)) {
|
| + uri = path.toUri(
|
| + path.join('assets', package.name, path.relative(assetPath, from: assetDir)));
|
| + } else {
|
| + continue;
|
| + }
|
| + return Future.wait(_directories.values.map((dir) {
|
| + return dir.server.then((server) => server.url.resolveUri(uri));
|
| + }));
|
| + }
|
| + return new Future.value([]);
|
| + }
|
| + Future<AssetId> getAssetIdForUrl(Uri url) {
|
| + return Future.wait(
|
| + _directories.values.map((dir) => dir.server)).then((servers) {
|
| + var server = servers.firstWhere((server) {
|
| + if (server.port != url.port) return false;
|
| + return isLoopback(server.address.host) == isLoopback(url.host) ||
|
| + server.address.host == url.host;
|
| + }, orElse: () => null);
|
| + if (server == null) return null;
|
| + return server.urlToId(url);
|
| + });
|
| + }
|
| + bool containsPath(String sourcePath) {
|
| + var directories = ["lib"];
|
| + directories.addAll(_directories.keys);
|
| + return directories.any((dir) => path.isWithin(dir, sourcePath));
|
| + }
|
| + void pauseUpdates() {
|
| + assert(_modifiedSources == null);
|
| + _modifiedSources = new Set<AssetId>();
|
| + }
|
| + void resumeUpdates() {
|
| + assert(_modifiedSources != null);
|
| + barback.updateSources(_modifiedSources);
|
| + _modifiedSources = null;
|
| + }
|
| + Future _load({bool useDart2JS}) {
|
| + return log.progress("Initializing barback", () {
|
| + var containsDart2JS = graph.entrypoint.root.pubspec.transformers.any(
|
| + (transformers) =>
|
| + transformers.any((config) => config.id.package == '\$dart2js'));
|
| + if (!containsDart2JS && useDart2JS) {
|
| + _builtInTransformers.addAll(
|
| + [new Dart2JSTransformer(this, mode), new DartForwardingTransformer(mode)]);
|
| + }
|
| + var dartPath = assetPath('dart');
|
| + var pubSources = listDir(
|
| + dartPath,
|
| + recursive: true).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());
|
| + });
|
| + var libPath = path.join(sdk.rootDirectory, "lib");
|
| + var sdkSources = listDir(
|
| + libPath,
|
| + recursive: true).where((file) => path.extension(file) == ".dart").map((file) {
|
| + var idPath =
|
| + path.join("lib", path.relative(file, from: sdk.rootDirectory));
|
| + return new AssetId('\$sdk', path.toUri(idPath).toString());
|
| + });
|
| + var transformerServer;
|
| + return BarbackServer.bind(this, _hostname, 0).then((server) {
|
| + transformerServer = server;
|
| + var errorStream = barback.errors.map((error) {
|
| + 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();
|
| + var errorStream = barback.errors.map((error) {
|
| + if (error is! TransformerException) throw error;
|
| + 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 log.progress("Loading transformers", () {
|
| + return loadAllTransformers(
|
| + this,
|
| + transformerServer).then((_) => transformerServer.close());
|
| + }, fine: true);
|
| + }, [errorStream, barback.results, transformerServer.results]);
|
| + }).then((_) => barback.removeSources(pubSources));
|
| + }, fine: true);
|
| + }
|
| + Future _provideSources() {
|
| + return Future.wait(packages.map((package) {
|
| + return _provideDirectorySources(graph.packages[package], "lib");
|
| + }));
|
| + }
|
| + Future<StreamSubscription<WatchEvent>>
|
| + _provideDirectorySources(Package package, String dir) {
|
| + log.fine("Providing sources for ${package.name}|$dir.");
|
| + if (_watcherType == WatcherType.NONE) {
|
| + _updateDirectorySources(package, dir);
|
| + return new Future.value();
|
| + }
|
| + return _watchDirectorySources(package, dir).then((_) {
|
| + _updateDirectorySources(package, dir);
|
| + });
|
| + }
|
| + void _updateDirectorySources(Package package, String dir) {
|
| + var ids = _listDirectorySources(package, dir);
|
| + if (_modifiedSources == null) {
|
| + barback.updateSources(ids);
|
| + } else {
|
| + _modifiedSources.addAll(ids);
|
| + }
|
| + }
|
| + void _removeDirectorySources(String dir) {
|
| + var ids = _listDirectorySources(rootPackage, dir);
|
| + if (_modifiedSources == null) {
|
| + barback.removeSources(ids);
|
| + } else {
|
| + _modifiedSources.removeAll(ids);
|
| + }
|
| + }
|
| + Iterable<AssetId> _listDirectorySources(Package package, String dir) {
|
| + var subdirectory = path.join(package.dir, dir);
|
| + if (!dirExists(subdirectory)) return [];
|
| + return package.listFiles(beneath: subdirectory).map((file) {
|
| + var relative = path.relative(file, from: package.dir);
|
| + if (Platform.operatingSystem == 'windows') {
|
| + relative = relative.replaceAll("\\", "/");
|
| + }
|
| + var uri = new Uri(pathSegments: relative.split("/"));
|
| + return new AssetId(package.name, uri.toString());
|
| + });
|
| + }
|
| + Future<StreamSubscription<WatchEvent>> _watchDirectorySources(Package package,
|
| + String dir) {
|
| + var packageId = graph.lockFile.packages[package.name];
|
| + if (packageId != null &&
|
| + graph.entrypoint.cache.sources[packageId.source] is CachedSource) {
|
| + return new Future.value();
|
| + }
|
| + var subdirectory = path.join(package.dir, dir);
|
| + if (!dirExists(subdirectory)) return new Future.value();
|
| + var watcher = _watcherType.create(subdirectory);
|
| + var subscription = watcher.events.listen((event) {
|
| + var parts = path.split(event.path);
|
| + if (parts.contains("packages")) return;
|
| + if (event.path.endsWith(".dart.js")) return;
|
| + if (event.path.endsWith(".dart.js.map")) return;
|
| + if (event.path.endsWith(".dart.precompiled.js")) return;
|
| + var idPath = path.relative(event.path, from: package.dir);
|
| + var id = new AssetId(package.name, path.toUri(idPath).toString());
|
| + if (event.type == ChangeType.REMOVE) {
|
| + if (_modifiedSources != null) {
|
| + _modifiedSources.remove(id);
|
| + } else {
|
| + barback.removeSources([id]);
|
| + }
|
| + } else if (_modifiedSources != null) {
|
| + _modifiedSources.add(id);
|
| + } else {
|
| + barback.updateSources([id]);
|
| + }
|
| + });
|
| + return watcher.ready.then((_) => subscription);
|
| + }
|
| + 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();
|
| + }
|
| + });
|
| + }
|
| +}
|
| +void _log(LogEntry entry) {
|
| + messageMentions(text) =>
|
| + entry.message.toLowerCase().contains(text.toLowerCase());
|
| + messageMentionsAsset(id) =>
|
| + messageMentions(id.toString()) ||
|
| + messageMentions(path.fromUri(entry.assetId.path));
|
| + var prefixParts = [];
|
| + if (!messageMentions(entry.level.name)) {
|
| + prefixParts.add("${entry.level} from");
|
| + }
|
| + prefixParts.add(entry.transform.transformer);
|
| + if (!messageMentionsAsset(entry.transform.primaryId)) {
|
| + prefixParts.add("on ${entry.transform.primaryId}");
|
| + }
|
| + if (entry.assetId != entry.transform.primaryId &&
|
| + !messageMentionsAsset(entry.assetId)) {
|
| + prefixParts.add("with input ${entry.assetId}");
|
| + }
|
| + var prefix = "[${prefixParts.join(' ')}]:";
|
| + var message = entry.message;
|
| + if (entry.span != null) {
|
| + message = entry.span.message(entry.message);
|
| + }
|
| + switch (entry.level) {
|
| + case LogLevel.ERROR:
|
| + log.error("${log.red(prefix)}\n$message");
|
| + break;
|
| + case LogLevel.WARNING:
|
| + log.warning("${log.yellow(prefix)}\n$message");
|
| + break;
|
| + case LogLevel.INFO:
|
| + log.message("${log.cyan(prefix)}\n$message");
|
| + break;
|
| + case LogLevel.FINE:
|
| + log.fine("${log.gray(prefix)}\n$message");
|
| + break;
|
| + }
|
| +}
|
| +class OverlappingSourceDirectoryException implements Exception {
|
| + final List<String> overlappingDirectories;
|
| + OverlappingSourceDirectoryException(this.overlappingDirectories);
|
| +}
|
| +abstract class WatcherType {
|
| + static const AUTO = const _AutoWatcherType();
|
| + static const POLLING = const _PollingWatcherType();
|
| + static const NONE = const _NoneWatcherType();
|
| + DirectoryWatcher create(String directory);
|
| + String toString();
|
| +}
|
| +class _AutoWatcherType implements WatcherType {
|
| + const _AutoWatcherType();
|
| + DirectoryWatcher create(String directory) => new DirectoryWatcher(directory);
|
| + String toString() => "auto";
|
| +}
|
| +class _PollingWatcherType implements WatcherType {
|
| + const _PollingWatcherType();
|
| + DirectoryWatcher create(String directory) =>
|
| + new PollingDirectoryWatcher(directory);
|
| + String toString() => "polling";
|
| +}
|
| +class _NoneWatcherType implements WatcherType {
|
| + const _NoneWatcherType();
|
| + DirectoryWatcher create(String directory) => null;
|
| + String toString() => "none";
|
| +}
|
|
|