Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 /** | |
| 6 * Temporary deploy command used to create a version of the app that can be | |
| 7 * compiled with dart2js and deployed. This library should go away once `pub | |
| 8 * deploy` can be configured to run barback transformers. | |
| 9 * | |
| 10 * From an application package you can run this program by calling dart with a | |
| 11 * 'package:' url to this file: | |
| 12 * | |
| 13 * dart package:polymer/deploy.dart | |
| 14 */ | |
| 15 library polymer.deploy; | |
| 16 | |
| 17 import 'dart:async'; | |
| 18 import 'dart:io'; | |
| 19 import 'dart:json' as json; | |
| 20 | |
| 21 import 'package:barback/barback.dart'; | |
| 22 import 'package:path/path.dart' as path; | |
| 23 import 'package:polymer/src/transform.dart' show phases; | |
| 24 import 'package:stack_trace/stack_trace.dart'; | |
| 25 import 'package:yaml/yaml.dart'; | |
| 26 | |
| 27 main() { | |
| 28 print('polymer/deploy.dart: creating a deploy target for "$_currentPackage"'); | |
| 29 var barback = new Barback(new _PolymerDeployProvider()); | |
| 30 _initializeBarback(barback); | |
| 31 _attachListeners(barback); | |
| 32 _emitAllFiles(barback); | |
| 33 } | |
| 34 | |
| 35 /** Tell barback which transformers to use and which assets to process. */ | |
| 36 void _initializeBarback(Barback barback) { | |
| 37 var assets = []; | |
| 38 for (var package in _packageDirs.keys) { | |
| 39 // Do not process packages like 'polymer' where there is nothing to do. | |
| 40 if (_ignoredPackages.contains(package)) continue; | |
| 41 barback.updateTransformers(package, phases); | |
| 42 | |
| 43 // notify barback to process anything under 'lib' and 'asset' | |
| 44 for (var filepath in _listDir(package, 'lib')) { | |
| 45 assets.add(new AssetId(package, filepath)); | |
| 46 } | |
| 47 | |
| 48 for (var filepath in _listDir(package, 'asset')) { | |
| 49 assets.add(new AssetId(package, filepath)); | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 // In case of the current package, include also 'web'. | |
| 54 for (var filepath in _listDir(_currentPackage, 'web')) { | |
| 55 assets.add(new AssetId(_currentPackage, filepath)); | |
| 56 } | |
| 57 barback.updateSources(assets); | |
| 58 } | |
| 59 | |
| 60 /** Return the relative path of each file under [subDir] in a [package]. */ | |
| 61 Iterable<String> _listDir(String package, String subDir) { | |
| 62 var packageDir = _packageDirs[package]; | |
| 63 if (packageDir == null) return const []; | |
| 64 var dir = new Directory(path.join(packageDir, subDir)); | |
| 65 if (!dir.existsSync()) return const []; | |
| 66 return dir.listSync(recursive: true, followLinks: false) | |
| 67 .where((f) => f is File) | |
| 68 .map((f) => path.relative(f.path, from: packageDir)); | |
| 69 } | |
| 70 | |
| 71 /** Attach error listeners on [barback] so we can report errors. */ | |
| 72 void _attachListeners(Barback barback) { | |
| 73 // Listen for errors and results | |
| 74 barback.errors.listen((e) { | |
| 75 var trace = getAttachedStackTrace(e); | |
| 76 if (trace != null) { | |
| 77 print(Trace.format(trace)); | |
| 78 } | |
| 79 print('error running barback: $e'); | |
| 80 exit(1); | |
| 81 }); | |
| 82 | |
| 83 barback.results.listen((result) { | |
| 84 if (!result.succeeded) { | |
| 85 print("build failed with errors: ${result.errors}"); | |
| 86 exit(1); | |
| 87 } | |
| 88 }); | |
| 89 } | |
| 90 | |
| 91 /** Ensure [dirpath] exists. */ | |
| 92 void _ensureDir(var dirpath) { | |
| 93 new Directory(dirpath).createSync(recursive: true); | |
| 94 } | |
| 95 | |
| 96 /** | |
| 97 * Emits all outputs of [barback] and copies files that we didn't process (like | |
| 98 * polymer's libraries). | |
| 99 */ | |
| 100 Future _emitAllFiles(Barback barback) { | |
| 101 return barback.getAllAssets().then((assets) { | |
| 102 // Copy all the assets we transformed | |
| 103 var futures = []; | |
| 104 for (var asset in assets) { | |
| 105 var id = asset.id; | |
| 106 var filepath; | |
| 107 if (id.package == _currentPackage && id.path.startsWith('web/')) { | |
| 108 filepath = path.join('out', id.path); | |
|
Jennifer Messerly
2013/08/23 02:07:00
should the "out" folder be configurable?
Siggi Cherem (dart-lang)
2013/08/23 02:30:55
haha, I had a TODO for that, and somehow deleted i
| |
| 109 } else if (id.path.startsWith('lib/')) { | |
| 110 filepath = path.join('out', 'web', 'packages', id.package, | |
| 111 id.path.substring(4)); | |
| 112 } else { | |
| 113 // TODO(sigmund): do something about other assets? | |
| 114 continue; | |
| 115 } | |
| 116 | |
| 117 _ensureDir(path.dirname(filepath)); | |
| 118 futures.add(asset.readAsString() | |
| 119 .then((content) => new File(filepath).writeAsStringSync(content))); | |
| 120 } | |
| 121 return Future.wait(futures); | |
| 122 }).then((_) { | |
| 123 // Copy also all the files we didn't process | |
| 124 for (var package in _ignoredPackages) { | |
| 125 for (var relpath in _listDir(package, 'lib')) { | |
| 126 var inpath = path.join(_packageDirs[package], relpath); | |
| 127 var outpath = path.join('out', 'web', 'packages', package, | |
| 128 relpath.substring(4)); | |
| 129 _ensureDir(path.dirname(outpath)); | |
| 130 new File(outpath).writeAsBytesSync(new File(inpath).readAsBytesSync()); | |
|
Jennifer Messerly
2013/08/23 02:07:00
this might be a good use case for async reading/wr
Siggi Cherem (dart-lang)
2013/08/23 02:30:55
Nice, Done.
| |
| 131 } | |
| 132 } | |
| 133 print('Done! All files written under the "out" directory'); | |
| 134 }); | |
| 135 } | |
| 136 | |
| 137 /** A simple provider that reads files directly from the pub cache. */ | |
| 138 class _PolymerDeployProvider implements PackageProvider { | |
| 139 | |
| 140 Iterable<String> get packages => _packageDirs.keys; | |
| 141 _PolymerDeployProvider(); | |
| 142 | |
| 143 Future<Asset> getAsset(AssetId id) => | |
| 144 new Future.value(new Asset.fromPath(id, path.join( | |
| 145 _packageDirs[id.package], | |
| 146 // Assets always use the posix style paths | |
| 147 path.joinAll(path.posix.split(id.path))))); | |
| 148 } | |
| 149 | |
| 150 | |
| 151 /** The current package extracted from the pubspec.yaml file. */ | |
| 152 String _currentPackage = () { | |
| 153 var pubspec = new File('pubspec.yaml'); | |
| 154 if (!pubspec.existsSync()) { | |
| 155 print('error: pubspec.yaml file not found, please run this script from ' | |
| 156 'your package root directory.'); | |
| 157 return null; | |
| 158 } | |
| 159 return loadYaml(pubspec.readAsStringSync())['name']; | |
| 160 }(); | |
| 161 | |
| 162 /** | |
| 163 * Maps package names to the path in the file system where to find the sources | |
| 164 * of such package. This map will contain an entry for the current package and | |
| 165 * everything it depends on (extracted via `pub list-pacakge-dirs`). | |
| 166 */ | |
| 167 Map<String, String> _packageDirs = () { | |
| 168 var pub = path.join(path.dirname(new Options().executable), | |
| 169 Platform.isWindows ? 'pub.bat' : 'pub'); | |
| 170 var result = Process.runSync(pub, ['list-package-dirs']); | |
| 171 if (result.exitCode != 0) { | |
| 172 print("unexpected error invoking 'pub':"); | |
| 173 print(result.stdout); | |
| 174 print(result.stderr); | |
| 175 exit(result.exitCode); | |
| 176 } | |
| 177 var map = json.parse(result.stdout)["packages"]; | |
| 178 map.forEach((k, v) { map[k] = path.dirname(v); }); | |
| 179 map[_currentPackage] = '.'; | |
| 180 return map; | |
| 181 }(); | |
| 182 | |
| 183 /** | |
| 184 * Internal packages used by polymer which we can copy directly to the output | |
| 185 * folder without having to process them with barback. | |
| 186 */ | |
| 187 Set<String> _ignoredPackages = | |
| 188 (const [ 'analyzer_experimental', 'args', 'barback', 'browser', 'csslib', | |
|
Jennifer Messerly
2013/08/23 02:07:00
hmm, I wonder if there's anywhere else we can get
Siggi Cherem (dart-lang)
2013/08/23 02:30:55
Added a TODO.
Pub makes it easy to do this for th
| |
| 189 'custom_element', 'fancy_syntax', 'html5lib', 'html_import', 'js', | |
| 190 'logging', 'mdv', 'meta', 'mutation_observer', 'observe', 'path', | |
| 191 'polymer', 'polymer_expressions', 'serialization', 'shadow_dom', | |
| 192 'source_maps', 'stack_trace', 'unittest', | |
| 193 'unmodifiable_collection', 'yaml' | |
| 194 ]).toSet(); | |
| OLD | NEW |