Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library pub.barback.asset_environment; | 5 library pub.barback.asset_environment; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:barback/barback.dart'; | 10 import 'package:barback/barback.dart'; |
| 11 import 'package:path/path.dart' as path; | 11 import 'package:path/path.dart' as path; |
| 12 import 'package:watcher/watcher.dart'; | 12 import 'package:watcher/watcher.dart'; |
| 13 | 13 |
| 14 import '../cached_package.dart'; | |
| 14 import '../entrypoint.dart'; | 15 import '../entrypoint.dart'; |
| 15 import '../exceptions.dart'; | 16 import '../exceptions.dart'; |
| 16 import '../io.dart'; | 17 import '../io.dart'; |
| 17 import '../log.dart' as log; | 18 import '../log.dart' as log; |
| 18 import '../package.dart'; | 19 import '../package.dart'; |
| 19 import '../package_graph.dart'; | 20 import '../package_graph.dart'; |
| 20 import '../sdk.dart' as sdk; | 21 import '../sdk.dart' as sdk; |
| 21 import '../source/cached.dart'; | 22 import '../source/cached.dart'; |
| 22 import '../utils.dart'; | 23 import '../utils.dart'; |
| 23 import 'admin_server.dart'; | 24 import 'admin_server.dart'; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 /// transformers, and server are loaded and ready. | 60 /// transformers, and server are loaded and ready. |
| 60 static Future<AssetEnvironment> create(Entrypoint entrypoint, | 61 static Future<AssetEnvironment> create(Entrypoint entrypoint, |
| 61 BarbackMode mode, {WatcherType watcherType, String hostname, int basePort, | 62 BarbackMode mode, {WatcherType watcherType, String hostname, int basePort, |
| 62 Iterable<String> packages, bool useDart2JS: true}) { | 63 Iterable<String> packages, bool useDart2JS: true}) { |
| 63 if (watcherType == null) watcherType = WatcherType.NONE; | 64 if (watcherType == null) watcherType = WatcherType.NONE; |
| 64 if (hostname == null) hostname = "localhost"; | 65 if (hostname == null) hostname = "localhost"; |
| 65 if (basePort == null) basePort = 0; | 66 if (basePort == null) basePort = 0; |
| 66 | 67 |
| 67 return entrypoint.loadPackageGraph().then((graph) { | 68 return entrypoint.loadPackageGraph().then((graph) { |
| 68 log.fine("Loaded package graph."); | 69 log.fine("Loaded package graph."); |
| 69 var barback = new Barback(new PubPackageProvider(graph, packages)); | 70 graph = _adjustPackageGraph(graph, mode, packages); |
| 71 var barback = new Barback(new PubPackageProvider(graph)); | |
| 70 barback.log.listen(_log); | 72 barback.log.listen(_log); |
| 71 | 73 |
| 72 var environment = new AssetEnvironment._(graph, barback, mode, | 74 var environment = new AssetEnvironment._(graph, barback, mode, |
| 73 watcherType, hostname, basePort, packages); | 75 watcherType, hostname, basePort); |
| 74 | 76 |
| 75 return environment._load(useDart2JS: useDart2JS) | 77 return environment._load(useDart2JS: useDart2JS) |
| 76 .then((_) => environment); | 78 .then((_) => environment); |
| 77 }); | 79 }); |
| 78 } | 80 } |
| 79 | 81 |
| 82 /// Return a version of [graph] that's restricted to [packages] (if passed) | |
| 83 /// and loads cached packages (if [mode] is [BarbackMode.DEBUG]). | |
| 84 static PackageGraph _adjustPackageGraph(PackageGraph graph, | |
| 85 BarbackMode mode, Iterable<String> packages) { | |
| 86 if (mode != BarbackMode.DEBUG && packages == null) return graph; | |
| 87 packages = (packages == null ? graph.packages.keys : packages).toSet(); | |
| 88 | |
| 89 return new PackageGraph(graph.entrypoint, graph.lockFile, | |
| 90 new Map.fromIterable(packages, value: (packageName) { | |
| 91 var package = graph.packages[packageName]; | |
| 92 if (mode != BarbackMode.DEBUG) return package; | |
| 93 var cache = path.join('.pub/deps/debug', packageName); | |
| 94 if (!dirExists(cache)) return package; | |
| 95 return new CachedPackage(package, cache); | |
| 96 })); | |
| 97 } | |
| 98 | |
| 80 /// The server for the Web Socket API and admin interface. | 99 /// The server for the Web Socket API and admin interface. |
| 81 AdminServer _adminServer; | 100 AdminServer _adminServer; |
| 82 | 101 |
| 83 /// The public directories in the root package that are included in the asset | 102 /// The public directories in the root package that are included in the asset |
| 84 /// environment, keyed by their root directory. | 103 /// environment, keyed by their root directory. |
| 85 final _directories = new Map<String, SourceDirectory>(); | 104 final _directories = new Map<String, SourceDirectory>(); |
| 86 | 105 |
| 87 /// The [Barback] instance used to process assets in this environment. | 106 /// The [Barback] instance used to process assets in this environment. |
| 88 final Barback barback; | 107 final Barback barback; |
| 89 | 108 |
| 90 /// The root package being built. | 109 /// The root package being built. |
| 91 Package get rootPackage => graph.entrypoint.root; | 110 Package get rootPackage => graph.entrypoint.root; |
| 92 | 111 |
| 93 /// The underlying [PackageGraph] being built. | 112 /// The graph of packages whose assets and transformers are loaded in this |
| 113 /// environment. | |
| 114 /// | |
| 115 /// This isn't necessarily identical to the graph that's passed in to the | |
| 116 /// environment. It may expose fewer packages if some packages' assets don't | |
| 117 /// need to be loaded, and it may expose some [CachedPackage]s. | |
| 94 final PackageGraph graph; | 118 final PackageGraph graph; |
| 95 | 119 |
| 96 /// The mode to run the transformers in. | 120 /// The mode to run the transformers in. |
| 97 final BarbackMode mode; | 121 final BarbackMode mode; |
| 98 | 122 |
| 99 /// The [Transformer]s that should be appended by default to the root | 123 /// The [Transformer]s that should be appended by default to the root |
| 100 /// package's transformer cascade. Will be empty if there are none. | 124 /// package's transformer cascade. Will be empty if there are none. |
| 101 final _builtInTransformers = <Transformer>[]; | 125 final _builtInTransformers = <Transformer>[]; |
| 102 | 126 |
| 103 /// How source files should be watched. | 127 /// How source files should be watched. |
| 104 final WatcherType _watcherType; | 128 final WatcherType _watcherType; |
| 105 | 129 |
| 106 /// The hostname that servers are bound to. | 130 /// The hostname that servers are bound to. |
| 107 final String _hostname; | 131 final String _hostname; |
| 108 | 132 |
| 109 /// The starting number for ports that servers will be bound to. | 133 /// The starting number for ports that servers will be bound to. |
| 110 /// | 134 /// |
| 111 /// Servers will be bound to ports starting at this number and then | 135 /// Servers will be bound to ports starting at this number and then |
| 112 /// incrementing from there. However, if this is zero, then ephemeral port | 136 /// incrementing from there. However, if this is zero, then ephemeral port |
| 113 /// numbers will be selected for each server. | 137 /// numbers will be selected for each server. |
| 114 final int _basePort; | 138 final int _basePort; |
| 115 | 139 |
| 116 /// The set of all packages that are visible for this environment. | |
| 117 /// | |
| 118 /// By default, this is all transitive dependencies of the entrypoint, but it | |
| 119 /// may be a narrower set if fewer packages are needed. | |
| 120 final Set<String> packages; | |
| 121 | |
| 122 /// The modified source assets that have not been sent to barback yet. | 140 /// The modified source assets that have not been sent to barback yet. |
| 123 /// | 141 /// |
| 124 /// The build environment can be paused (by calling [pauseUpdates]) and | 142 /// The build environment can be paused (by calling [pauseUpdates]) and |
| 125 /// resumed ([resumeUpdates]). While paused, all source asset updates that | 143 /// resumed ([resumeUpdates]). While paused, all source asset updates that |
| 126 /// come from watching or adding new directories are not sent to barback. | 144 /// come from watching or adding new directories are not sent to barback. |
| 127 /// When resumed, all pending source updates are sent to barback. | 145 /// When resumed, all pending source updates are sent to barback. |
| 128 /// | 146 /// |
| 129 /// This lets pub serve and pub build create an environment and bind several | 147 /// This lets pub serve and pub build create an environment and bind several |
| 130 /// servers before barback starts building and producing results | 148 /// servers before barback starts building and producing results |
| 131 /// asynchronously. | 149 /// asynchronously. |
| 132 /// | 150 /// |
| 133 /// If this is `null`, then the environment is "live" and all updates will | 151 /// If this is `null`, then the environment is "live" and all updates will |
| 134 /// go to barback immediately. | 152 /// go to barback immediately. |
| 135 Set<AssetId> _modifiedSources; | 153 Set<AssetId> _modifiedSources; |
| 136 | 154 |
| 137 AssetEnvironment._(PackageGraph graph, this.barback, this.mode, | 155 AssetEnvironment._(this.graph, this.barback, this.mode, |
| 138 this._watcherType, this._hostname, this._basePort, | 156 this._watcherType, this._hostname, this._basePort); |
| 139 Iterable<String> packages) | |
| 140 : graph = graph, | |
| 141 packages = packages == null ? graph.packages.keys.toSet() : | |
| 142 packages.toSet(); | |
| 143 | 157 |
| 144 /// Gets the built-in [Transformer]s that should be added to [package]. | 158 /// Gets the built-in [Transformer]s that should be added to [package]. |
| 145 /// | 159 /// |
| 146 /// Returns `null` if there are none. | 160 /// Returns `null` if there are none. |
| 147 Iterable<Transformer> getBuiltInTransformers(Package package) { | 161 Iterable<Transformer> getBuiltInTransformers(Package package) { |
| 148 // Built-in transformers only apply to the root package. | 162 // Built-in transformers only apply to the root package. |
| 149 if (package.name != rootPackage.name) return null; | 163 if (package.name != rootPackage.name) return null; |
| 150 | 164 |
| 151 // The built-in transformers are for dart2js and forwarding assets around | 165 // The built-in transformers are for dart2js and forwarding assets around |
| 152 // dart2js. | 166 // dart2js. |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 var relativePath = path.relative(assetPath, from: dir.directory); | 344 var relativePath = path.relative(assetPath, from: dir.directory); |
| 331 return dir.server.then((server) => | 345 return dir.server.then((server) => |
| 332 server.url.resolveUri(path.toUri(relativePath))); | 346 server.url.resolveUri(path.toUri(relativePath))); |
| 333 })); | 347 })); |
| 334 } | 348 } |
| 335 | 349 |
| 336 /// Look up [assetPath] in the "packages" directory in the entrypoint package. | 350 /// Look up [assetPath] in the "packages" directory in the entrypoint package. |
| 337 Future<List<Uri>> _lookUpPathInPackagesDirectory(String assetPath) { | 351 Future<List<Uri>> _lookUpPathInPackagesDirectory(String assetPath) { |
| 338 var components = path.split(path.relative(assetPath)); | 352 var components = path.split(path.relative(assetPath)); |
| 339 if (components.first != "packages") return new Future.value([]); | 353 if (components.first != "packages") return new Future.value([]); |
| 340 if (!packages.contains(components[1])) return new Future.value([]); | 354 if (!graph.packages.containsKey(components[1])) return new Future.value([]); |
|
Bob Nystrom
2014/09/23 19:47:45
async?
nweiz
2014/09/23 21:34:50
I didn't want to make a bunch of async transformat
| |
| 341 return Future.wait(_directories.values.map((dir) { | 355 return Future.wait(_directories.values.map((dir) { |
| 342 return dir.server.then((server) => | 356 return dir.server.then((server) => |
| 343 server.url.resolveUri(path.toUri(assetPath))); | 357 server.url.resolveUri(path.toUri(assetPath))); |
| 344 })); | 358 })); |
| 345 } | 359 } |
| 346 | 360 |
| 347 /// Look up [assetPath] in the "lib" or "asset" directory of a dependency | 361 /// Look up [assetPath] in the "lib" or "asset" directory of a dependency |
| 348 /// package. | 362 /// package. |
| 349 Future<List<Uri>> _lookUpPathInDependency(String assetPath) { | 363 Future<List<Uri>> _lookUpPathInDependency(String assetPath) { |
| 350 for (var packageName in packages) { | 364 for (var packageName in graph.packages.keys) { |
| 351 var package = graph.packages[packageName]; | 365 var package = graph.packages[packageName]; |
| 352 var libDir = path.join(package.dir, 'lib'); | 366 var libDir = package.path('lib'); |
| 353 var assetDir = path.join(package.dir, 'asset'); | 367 var assetDir = package.path('asset'); |
| 354 | 368 |
| 355 var uri; | 369 var uri; |
| 356 if (path.isWithin(libDir, assetPath)) { | 370 if (path.isWithin(libDir, assetPath)) { |
| 357 uri = path.toUri(path.join('packages', package.name, | 371 uri = path.toUri(path.join('packages', package.name, |
| 358 path.relative(assetPath, from: libDir))); | 372 path.relative(assetPath, from: libDir))); |
| 359 } else if (path.isWithin(assetDir, assetPath)) { | 373 } else if (path.isWithin(assetDir, assetPath)) { |
| 360 uri = path.toUri(path.join('assets', package.name, | 374 uri = path.toUri(path.join('assets', package.name, |
| 361 path.relative(assetPath, from: assetDir))); | 375 path.relative(assetPath, from: assetDir))); |
| 362 } else { | 376 } else { |
| 363 continue; | 377 continue; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 }, fine: true); | 533 }, fine: true); |
| 520 } | 534 } |
| 521 | 535 |
| 522 /// Provides the public source assets in the environment to barback. | 536 /// Provides the public source assets in the environment to barback. |
| 523 /// | 537 /// |
| 524 /// If [watcherType] is not [WatcherType.NONE], enables watching on them. | 538 /// If [watcherType] is not [WatcherType.NONE], enables watching on them. |
| 525 Future _provideSources() { | 539 Future _provideSources() { |
| 526 // Just include the "lib" directory from each package. We'll add the | 540 // Just include the "lib" directory from each package. We'll add the |
| 527 // other build directories in the root package by calling | 541 // other build directories in the root package by calling |
| 528 // [serveDirectory]. | 542 // [serveDirectory]. |
| 529 return Future.wait(packages.map((package) { | 543 return Future.wait(graph.packages.values.map((package) { |
| 530 return _provideDirectorySources(graph.packages[package], "lib"); | 544 return _provideDirectorySources(package, "lib"); |
| 531 })); | 545 })); |
| 532 } | 546 } |
| 533 | 547 |
| 534 /// Provides all of the source assets within [dir] in [package] to barback. | 548 /// Provides all of the source assets within [dir] in [package] to barback. |
| 535 /// | 549 /// |
| 536 /// If [watcherType] is not [WatcherType.NONE], enables watching on them. | 550 /// If [watcherType] is not [WatcherType.NONE], enables watching on them. |
| 537 /// Returns the subscription to the watcher, or `null` if none was created. | 551 /// Returns the subscription to the watcher, or `null` if none was created. |
| 538 Future<StreamSubscription<WatchEvent>> _provideDirectorySources( | 552 Future<StreamSubscription<WatchEvent>> _provideDirectorySources( |
| 539 Package package, String dir) { | 553 Package package, String dir) { |
| 540 log.fine("Providing sources for ${package.name}|$dir."); | 554 log.fine("Providing sources for ${package.name}|$dir."); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 /// but slower [listDir]. | 598 /// but slower [listDir]. |
| 585 Iterable<AssetId> _listDirectorySources(Package package, String dir) { | 599 Iterable<AssetId> _listDirectorySources(Package package, String dir) { |
| 586 // This is used in some performance-sensitive paths and can list many, many | 600 // This is used in some performance-sensitive paths and can list many, many |
| 587 // files. As such, it leans more havily towards optimization as opposed to | 601 // files. As such, it leans more havily towards optimization as opposed to |
| 588 // readability than most code in pub. In particular, it avoids using the | 602 // readability than most code in pub. In particular, it avoids using the |
| 589 // path package, since re-parsing a path is very expensive relative to | 603 // path package, since re-parsing a path is very expensive relative to |
| 590 // string operations. | 604 // string operations. |
| 591 return package.listFiles(beneath: dir).map((file) { | 605 return package.listFiles(beneath: dir).map((file) { |
| 592 // From profiling, path.relative here is just as fast as a raw substring | 606 // From profiling, path.relative here is just as fast as a raw substring |
| 593 // and is correct in the case where package.dir has a trailing slash. | 607 // and is correct in the case where package.dir has a trailing slash. |
| 594 var relative = path.relative(file, from: package.dir); | 608 var relative = package.relative(file); |
| 595 | 609 |
| 596 if (Platform.operatingSystem == 'windows') { | 610 if (Platform.operatingSystem == 'windows') { |
| 597 relative = relative.replaceAll("\\", "/"); | 611 relative = relative.replaceAll("\\", "/"); |
| 598 } | 612 } |
| 599 | 613 |
| 600 var uri = new Uri(pathSegments: relative.split("/")); | 614 var uri = new Uri(pathSegments: relative.split("/")); |
| 601 return new AssetId(package.name, uri.toString()); | 615 return new AssetId(package.name, uri.toString()); |
| 602 }); | 616 }); |
| 603 } | 617 } |
| 604 | 618 |
| 605 /// Adds a file watcher for [dir] within [package], if the directory exists | 619 /// Adds a file watcher for [dir] within [package], if the directory exists |
| 606 /// and the package needs watching. | 620 /// and the package needs watching. |
| 607 Future<StreamSubscription<WatchEvent>> _watchDirectorySources( | 621 Future<StreamSubscription<WatchEvent>> _watchDirectorySources( |
| 608 Package package, String dir) { | 622 Package package, String dir) { |
| 609 // If this package comes from a cached source, its contents won't change so | 623 // If this package comes from a cached source, its contents won't change so |
| 610 // we don't need to monitor it. `packageId` will be null for the | 624 // we don't need to monitor it. `packageId` will be null for the |
| 611 // application package, since that's not locked. | 625 // application package, since that's not locked. |
| 612 var packageId = graph.lockFile.packages[package.name]; | 626 var packageId = graph.lockFile.packages[package.name]; |
| 613 if (packageId != null && | 627 if (packageId != null && |
| 614 graph.entrypoint.cache.sources[packageId.source] is CachedSource) { | 628 graph.entrypoint.cache.sources[packageId.source] is CachedSource) { |
| 615 return new Future.value(); | 629 return new Future.value(); |
| 616 } | 630 } |
| 617 | 631 |
| 618 var subdirectory = path.join(package.dir, dir); | 632 var subdirectory = package.path(dir); |
| 619 if (!dirExists(subdirectory)) return new Future.value(); | 633 if (!dirExists(subdirectory)) return new Future.value(); |
| 620 | 634 |
| 621 // TODO(nweiz): close this watcher when [barback] is closed. | 635 // TODO(nweiz): close this watcher when [barback] is closed. |
| 622 var watcher = _watcherType.create(subdirectory); | 636 var watcher = _watcherType.create(subdirectory); |
| 623 var subscription = watcher.events.listen((event) { | 637 var subscription = watcher.events.listen((event) { |
| 624 // Don't watch files symlinked into these directories. | 638 // Don't watch files symlinked into these directories. |
| 625 // TODO(rnystrom): If pub gets rid of symlinks, remove this. | 639 // TODO(rnystrom): If pub gets rid of symlinks, remove this. |
| 626 var parts = path.split(event.path); | 640 var parts = path.split(event.path); |
| 627 if (parts.contains("packages")) return; | 641 if (parts.contains("packages")) return; |
| 628 | 642 |
| 629 // Skip files that were (most likely) compiled from nearby ".dart" | 643 // Skip files that were (most likely) compiled from nearby ".dart" |
| 630 // files. These are created by the Editor's "Run as JavaScript" | 644 // files. These are created by the Editor's "Run as JavaScript" |
| 631 // command and are written directly into the package's directory. | 645 // command and are written directly into the package's directory. |
| 632 // When pub's dart2js transformer then tries to create the same file | 646 // When pub's dart2js transformer then tries to create the same file |
| 633 // name, we get a build error. To avoid that, just don't consider | 647 // name, we get a build error. To avoid that, just don't consider |
| 634 // that file to be a source. | 648 // that file to be a source. |
| 635 // TODO(rnystrom): Remove these when the Editor no longer generates | 649 // TODO(rnystrom): Remove these when the Editor no longer generates |
| 636 // .js files and users have had enough time that they no longer have | 650 // .js files and users have had enough time that they no longer have |
| 637 // these files laying around. See #15859. | 651 // these files laying around. See #15859. |
| 638 if (event.path.endsWith(".dart.js")) return; | 652 if (event.path.endsWith(".dart.js")) return; |
| 639 if (event.path.endsWith(".dart.js.map")) return; | 653 if (event.path.endsWith(".dart.js.map")) return; |
| 640 if (event.path.endsWith(".dart.precompiled.js")) return; | 654 if (event.path.endsWith(".dart.precompiled.js")) return; |
| 641 | 655 |
| 642 var idPath = path.relative(event.path, from: package.dir); | 656 var idPath = package.relative(event.path); |
| 643 var id = new AssetId(package.name, path.toUri(idPath).toString()); | 657 var id = new AssetId(package.name, path.toUri(idPath).toString()); |
| 644 if (event.type == ChangeType.REMOVE) { | 658 if (event.type == ChangeType.REMOVE) { |
| 645 if (_modifiedSources != null) { | 659 if (_modifiedSources != null) { |
| 646 _modifiedSources.remove(id); | 660 _modifiedSources.remove(id); |
| 647 } else { | 661 } else { |
| 648 barback.removeSources([id]); | 662 barback.removeSources([id]); |
| 649 } | 663 } |
| 650 } else if (_modifiedSources != null) { | 664 } else if (_modifiedSources != null) { |
| 651 _modifiedSources.add(id); | 665 _modifiedSources.add(id); |
| 652 } else { | 666 } else { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 String toString() => "polling"; | 803 String toString() => "polling"; |
| 790 } | 804 } |
| 791 | 805 |
| 792 class _NoneWatcherType implements WatcherType { | 806 class _NoneWatcherType implements WatcherType { |
| 793 const _NoneWatcherType(); | 807 const _NoneWatcherType(); |
| 794 | 808 |
| 795 DirectoryWatcher create(String directory) => null; | 809 DirectoryWatcher create(String directory) => null; |
| 796 | 810 |
| 797 String toString() => "none"; | 811 String toString() => "none"; |
| 798 } | 812 } |
| OLD | NEW |