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"; |
+} |