| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, 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 * Common logic to make it easy to run the polymer linter and deploy tool. |
| 7 * |
| 8 * The functions in this library are designed to make it easier to create |
| 9 * `build.dart` files. A `build.dart` file is a Dart script that can be invoked |
| 10 * from the command line, but that can also invoked automatically by the Dart |
| 11 * Editor whenever a file in your project changes or when selecting some menu |
| 12 * options, such as 'Reanalyze Sources'. |
| 13 * |
| 14 * To work correctly, place the `build.dart` in the root of your project (where |
| 15 * pubspec.yaml lives). The file must be named exactly `build.dart`. |
| 16 * |
| 17 * It's quite likely that in the near future `build.dart` will be replaced with |
| 18 * something else. For example, `pub deploy` will deal with deploying |
| 19 * applications automatically, and the Dart Editor might provide other |
| 20 * mechanisms to hook linters. |
| 21 * |
| 22 * There are three important functions exposed by this library [build], [lint], |
| 23 * and [deploy]. The following examples show common uses of these functions when |
| 24 * writing a `build.dart` file. |
| 25 * |
| 26 * **Example 1**: Uses build.dart to run the linter tool. |
| 27 * |
| 28 * import 'dart:io'; |
| 29 * import 'package:polymer/builder.dart'; |
| 30 * |
| 31 * main() { |
| 32 * lint(); |
| 33 * } |
| 34 * |
| 35 * **Example 2**: Runs the linter and creates a deployable version of the app |
| 36 * every time. |
| 37 * |
| 38 * import 'dart:io'; |
| 39 * import 'package:polymer/builder.dart'; |
| 40 * |
| 41 * main() { |
| 42 * lint().then(() => deploy()); |
| 43 * } |
| 44 * |
| 45 * **Example 3**: Runs the linter, but conditionally does the deploy step. See |
| 46 * [parseOptions] for a description of options parsed automatically by this |
| 47 * helper library. |
| 48 * |
| 49 * import 'dart:io'; |
| 50 * import 'package:polymer/builder.dart'; |
| 51 * |
| 52 * main() { |
| 53 * var options = parseOptions(); |
| 54 * lint().then(() { |
| 55 * if (options.forceDeploy) deploy(); |
| 56 * }); |
| 57 * } |
| 58 * |
| 59 * **Example 4**: Same as above, but uses [build] (which internally calls [lint] |
| 60 * and [deploy]). |
| 61 * |
| 62 * import 'dart:io'; |
| 63 * import 'package:polymer/builder.dart'; |
| 64 * |
| 65 * main() { |
| 66 * build(); |
| 67 * } |
| 68 * |
| 69 * **Example 5**: Like the previous example, but indicates to the linter and |
| 70 * deploy tool which files are actually used as entry point files. See the |
| 71 * documentation of [build] below for more details. |
| 72 * |
| 73 * import 'dart:io'; |
| 74 * import 'package:polymer/builder.dart'; |
| 75 * |
| 76 * main() { |
| 77 * build(entryPoints: ['web/index.html']); |
| 78 * } |
| 79 */ |
| 80 library polymer.builder; |
| 81 |
| 82 import 'dart:async'; |
| 83 import 'dart:io'; |
| 84 |
| 85 import 'package:args/args.dart'; |
| 86 |
| 87 import 'src/barback_runner.dart'; |
| 88 import 'src/linter.dart'; |
| 89 import 'src/transform.dart'; |
| 90 |
| 91 |
| 92 /** |
| 93 * Runs the polymer linter on any relevant file in your package, such as any |
| 94 * .html file under 'lib/', 'asset/', and 'web/'. And, if requested, creates a |
| 95 * directory suitable for deploying a Polymer application to a server. |
| 96 * |
| 97 * The [entryPoints] list contains files under web/ that should be treated as |
| 98 * entry points. Each entry on this list is a relative path from the package |
| 99 * root (for example 'web/index.html'). If null, all files under 'web/' are |
| 100 * treated as possible entry points. |
| 101 * |
| 102 * Options are read from the command line arguments, but you can override them |
| 103 * passing the [options] argument. The deploy operation is run only when the |
| 104 * command-line argument `--deploy` is present, or equivalently when |
| 105 * `options.forceDeploy` is true. |
| 106 * |
| 107 * The linter and deploy steps needs to know the name of the [currentPackage] |
| 108 * and the location where to find the code for any package it depends on |
| 109 * ([packageDirs]). This is inferred automatically, but can be overriden if |
| 110 * those arguments are provided. |
| 111 */ |
| 112 Future build({List<String> entryPoints, CommandLineOptions options, |
| 113 String currentPackage, Map<String, String> packageDirs}) { |
| 114 if (options == null) options = _options; |
| 115 return lint(entryPoints: entryPoints, options: options, |
| 116 currentPackage: currentPackage, packageDirs: packageDirs).then((res) { |
| 117 if (options.forceDeploy) { |
| 118 return deploy(entryPoints: entryPoints, options: options, |
| 119 currentPackage: currentPackage, packageDirs: packageDirs); |
| 120 } |
| 121 }); |
| 122 } |
| 123 |
| 124 |
| 125 /** |
| 126 * Runs the polymer linter on any relevant file in your package, |
| 127 * such as any .html file under 'lib/', 'asset/', and 'web/'. |
| 128 * |
| 129 * The [entryPoints] list contains files under web/ that should be treated as |
| 130 * entry points. Each entry on this list is a relative path from the package |
| 131 * root (for example 'web/index.html'). If null, all files under 'web/' are |
| 132 * treated as possible entry points. |
| 133 * |
| 134 * Options are read from the command line arguments, but you can override them |
| 135 * passing the [options] argument. |
| 136 * |
| 137 * The linter needs to know the name of the [currentPackage] and the location |
| 138 * where to find the code for any package it depends on ([packageDirs]). This is |
| 139 * inferred automatically, but can be overriden if those arguments are provided. |
| 140 */ |
| 141 Future lint({List<String> entryPoints, CommandLineOptions options, |
| 142 String currentPackage, Map<String, String> packageDirs}) { |
| 143 if (options == null) options = _options; |
| 144 if (currentPackage == null) currentPackage = readCurrentPackageFromPubspec(); |
| 145 var linterOptions = new TransformOptions(currentPackage, entryPoints); |
| 146 var formatter = options.machineFormat ? jsonFormatter : consoleFormatter; |
| 147 var linter = new Linter(linterOptions, formatter); |
| 148 return runBarback(new BarbackOptions([[linter]], null, |
| 149 currentPackage: currentPackage, packageDirs: packageDirs)).then((assets) { |
| 150 var messages = {}; |
| 151 var futures = []; |
| 152 for (var asset in assets) { |
| 153 var id = asset.id; |
| 154 if (id.package == currentPackage && id.path.endsWith('.messages')) { |
| 155 futures.add(asset.readAsString().then((content) { |
| 156 if (content.isEmpty) return; |
| 157 messages[id] = content; |
| 158 })); |
| 159 } |
| 160 } |
| 161 |
| 162 return Future.wait(futures).then((_) { |
| 163 // Print messages sorting by package and filepath. |
| 164 var orderedKeys = messages.keys.toList(); |
| 165 orderedKeys.sort((a, b) { |
| 166 int packageCompare = a.package.compareTo(b.package); |
| 167 if (packageCompare != 0) return packageCompare; |
| 168 return a.path.compareTo(b.path); |
| 169 }); |
| 170 |
| 171 for (var key in orderedKeys) { |
| 172 print(messages[key]); |
| 173 } |
| 174 }); |
| 175 }); |
| 176 } |
| 177 |
| 178 /** |
| 179 * Creates a directory suitable for deploying a Polymer application to a server. |
| 180 * |
| 181 * **Note**: this function will be replaced in the future by the `pub deploy` |
| 182 * command. |
| 183 * |
| 184 * The [entryPoints] list contains files under web/ that should be treated as |
| 185 * entry points. Each entry on this list is a relative path from the package |
| 186 * root (for example 'web/index.html'). If null, all files under 'web/' are |
| 187 * treated as possible entry points. |
| 188 * |
| 189 * Options are read from the command line arguments, but you can override them |
| 190 * passing the [options] list. |
| 191 * |
| 192 * The deploy step needs to know the name of the [currentPackage] and the |
| 193 * location where to find the code for any package it depends on |
| 194 * ([packageDirs]). This is inferred automatically, but can be overriden if |
| 195 * those arguments are provided. |
| 196 */ |
| 197 Future deploy({List<String> entryPoints, CommandLineOptions options, |
| 198 String currentPackage, Map<String, String> packageDirs}) { |
| 199 if (options == null) options = _options; |
| 200 if (currentPackage == null) currentPackage = readCurrentPackageFromPubspec(); |
| 201 var barbackOptions = new BarbackOptions( |
| 202 createDeployPhases(new TransformOptions(currentPackage, entryPoints)), |
| 203 options.outDir, currentPackage: currentPackage, |
| 204 packageDirs: packageDirs); |
| 205 return runBarback(barbackOptions) |
| 206 .then((_) => print('Done! All files written to "${options.outDir}"')); |
| 207 } |
| 208 |
| 209 |
| 210 /** |
| 211 * Options that may be used either in build.dart or by the linter and deploy |
| 212 * tools. |
| 213 */ |
| 214 class CommandLineOptions { |
| 215 /** Files marked as changed. */ |
| 216 final List<String> changedFiles; |
| 217 |
| 218 /** Files marked as removed. */ |
| 219 final List<String> removedFiles; |
| 220 |
| 221 /** Whether to clean intermediate artifacts, if any. */ |
| 222 final bool clean; |
| 223 |
| 224 /** Whether to do a full build (as if all files have changed). */ |
| 225 final bool full; |
| 226 |
| 227 /** Whether to print results using a machine parseable format. */ |
| 228 final bool machineFormat; |
| 229 |
| 230 /** Whether the force deploy option was passed in the command line. */ |
| 231 final bool forceDeploy; |
| 232 |
| 233 /** Location where to generate output files. */ |
| 234 final String outDir; |
| 235 |
| 236 CommandLineOptions(this.changedFiles, this.removedFiles, this.clean, |
| 237 this.full, this.machineFormat, this.forceDeploy, this.outDir); |
| 238 } |
| 239 |
| 240 /** Options parsed directly from the command line arguments. */ |
| 241 CommandLineOptions _options = parseOptions(); |
| 242 |
| 243 /** |
| 244 * Parse command-line arguments and return a [CommandLineOptions] object. The |
| 245 * following flags are parsed by this method. |
| 246 * |
| 247 * * `--changed file-path`: notify of a file change. |
| 248 * * `--removed file-path`: notify that a file was removed. |
| 249 * * `--clean`: remove temporary artifacts (if any) |
| 250 * * `--full`: build everything, similar to marking every file as changed |
| 251 * * `--machine`: produce output that can be parsed by tools, such as the Dart |
| 252 * Editor. |
| 253 * * `--deploy`: force deploy. |
| 254 * * `--help`: print documentation for each option and exit. |
| 255 * |
| 256 * Currently not all the flags are used by [lint] or [deploy] above, but they |
| 257 * are available so they can be used from your `build.dart`. For instance, see |
| 258 * the top-level library documentation for an example that uses the force-deploy |
| 259 * option to conditionally call [deploy]. |
| 260 * |
| 261 * If this documentation becomes out of date, the best way to discover which |
| 262 * flags are supported is to invoke this function from your build.dart, and run |
| 263 * it with the `--help` command-line flag. |
| 264 */ |
| 265 CommandLineOptions parseOptions([List<String> args]) { |
| 266 var parser = new ArgParser() |
| 267 ..addOption('changed', help: 'The file has changed since the last build.', |
| 268 allowMultiple: true) |
| 269 ..addOption('removed', help: 'The file was removed since the last build.', |
| 270 allowMultiple: true) |
| 271 ..addFlag('clean', negatable: false, |
| 272 help: 'Remove any build artifacts (if any).') |
| 273 ..addFlag('full', negatable: false, help: 'perform a full build') |
| 274 ..addFlag('machine', negatable: false, |
| 275 help: 'Produce warnings in a machine parseable format.') |
| 276 ..addFlag('deploy', negatable: false, |
| 277 help: 'Whether to force deploying.') |
| 278 ..addOption('out', abbr: 'o', help: 'Directory to generate files into.', |
| 279 defaultsTo: 'out') |
| 280 ..addFlag('help', abbr: 'h', |
| 281 negatable: false, help: 'Displays this help and exit.'); |
| 282 var res = parser.parse(args == null ? new Options().arguments : args); |
| 283 if (res['help']) { |
| 284 print('A build script that invokes the polymer linter and deploy tools.'); |
| 285 print('Usage: dart build.dart [options]'); |
| 286 print('\nThese are valid options expected by build.dart:'); |
| 287 print(parser.getUsage()); |
| 288 exit(0); |
| 289 } |
| 290 return new CommandLineOptions(res['changed'], res['removed'], res['clean'], |
| 291 res['full'], res['machine'], res['deploy'], res['out']); |
| 292 } |
| OLD | NEW |