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 |