Index: sdk/lib/_internal/pub/lib/src/command/barback.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/command/barback.dart b/sdk/lib/_internal/pub/lib/src/command/barback.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a36a3720baa69b40145125726876917136728552 |
--- /dev/null |
+++ b/sdk/lib/_internal/pub/lib/src/command/barback.dart |
@@ -0,0 +1,182 @@ |
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library pub.command.barback; |
+ |
+import 'dart:async'; |
+ |
+import 'package:barback/barback.dart'; |
+import 'package:path/path.dart' as path; |
+ |
+import '../command.dart'; |
+import '../io.dart'; |
+import '../log.dart' as log; |
+import '../utils.dart'; |
+ |
+final _arrow = getSpecial('\u2192', '=>'); |
+ |
+/// The set of top level directories in the entrypoint package that are built |
+/// when the user does "--all". |
+final _allSourceDirectories = new Set<String>.from([ |
+ "benchmark", "bin", "example", "test", "web" |
+]); |
+ |
+/// Shared base class for [BuildCommand] and [ServeCommand]. |
+abstract class BarbackCommand extends PubCommand { |
+ final takesArguments = true; |
+ |
+ /// The build mode. |
+ BarbackMode get mode => new BarbackMode(commandOptions["mode"]); |
+ |
+ /// The directories in the entrypoint package that should be added to the |
+ /// build environment. |
+ final sourceDirectories = new Set<String>(); |
+ |
+ /// Override this to specify the default build mode. |
+ BarbackMode get defaultMode; |
+ |
+ /// Override this to specify the default source directories if none are |
+ /// provided on the command line. |
+ List<String> get defaultSourceDirectories; |
+ |
+ BarbackCommand() { |
+ commandParser.addOption("mode", defaultsTo: defaultMode.toString(), |
+ help: "Mode to run transformers in."); |
+ |
+ commandParser.addFlag("all", |
+ help: "Use all default source directories.", |
+ defaultsTo: false, negatable: false); |
+ } |
+ |
+ Future onRun() { |
+ // Switch to JSON output if specified. We need to do this before parsing |
+ // the source directories so an error will be correctly reported in JSON |
+ // format. |
+ log.json.enabled = commandOptions.options.contains("format") && |
+ commandOptions["format"] == "json"; |
+ |
+ _parseSourceDirectories(); |
+ return onRunTransformerCommand(); |
+ } |
+ |
+ /// Override this to run the actual command. |
+ Future onRunTransformerCommand(); |
+ |
+ /// Parses the command-line arguments to determine the set of source |
+ /// directories to add to the build environment. |
+ /// |
+ /// If there are no arguments, this will just be [defaultSourceDirectories]. |
+ /// |
+ /// If the `--all` flag is set, then it will be all default directories |
+ /// that exist. |
+ /// |
+ /// Otherwise, all arguments should be the paths of directories to include. |
+ /// |
+ /// Throws an exception if the arguments are invalid. |
+ void _parseSourceDirectories() { |
+ if (commandOptions["all"]) { |
+ _addAllDefaultSources(); |
+ return; |
+ } |
+ |
+ // If no directories were specified, use the defaults. |
+ if (commandOptions.rest.isEmpty) { |
+ _addDefaultSources(); |
+ return; |
+ } |
+ |
+ sourceDirectories.addAll(commandOptions.rest); |
+ |
+ // Prohibit "lib" and "asset". |
+ var disallowed = sourceDirectories.where((dir) { |
+ var parts = path.split(path.normalize(dir)); |
+ return parts.isNotEmpty && ["lib", "asset"].contains(parts.first); |
+ }); |
+ |
+ if (disallowed.isNotEmpty) { |
+ usageError(_directorySentence(disallowed, "is", "are", "not allowed")); |
+ } |
+ |
+ // Make sure the source directories don't reach out of the package. |
+ var invalid = sourceDirectories.where((dir) => !path.isWithin('.', dir)); |
+ if (invalid.isNotEmpty) { |
+ usageError(_directorySentence(invalid, "isn't", "aren't", |
+ "in this package")); |
+ } |
+ |
+ // Make sure all of the source directories exist. |
+ var missing = sourceDirectories.where( |
+ (dir) => !dirExists(path.join(entrypoint.root.dir, dir))); |
+ |
+ if (missing.isNotEmpty) { |
+ dataError(_directorySentence(missing, "does", "do", "not exist")); |
+ } |
+ } |
+ |
+ /// Handles "--all" by adding all default source directories that are |
+ /// present. |
+ void _addAllDefaultSources() { |
+ if (commandOptions.rest.isNotEmpty) { |
+ usageError( |
+ 'Directory names are not allowed if "--all" is passed.'); |
+ } |
+ |
+ // Include every build directory that exists in the package. |
+ var dirs = _allSourceDirectories.where( |
+ (dir) => dirExists(path.join(entrypoint.root.dir, dir))); |
+ |
+ if (dirs.isEmpty) { |
+ var defaultDirs = toSentence(_allSourceDirectories.map( |
+ (name) => '"$name"')); |
+ dataError('There are no source directories present.\n' |
+ 'The default directories are $defaultDirs.'); |
+ } |
+ |
+ sourceDirectories.addAll(dirs); |
+ } |
+ |
+ /// Adds the default sources that should be used if no directories are passed |
+ /// on the command line. |
+ void _addDefaultSources() { |
+ sourceDirectories.addAll(defaultSourceDirectories.where( |
+ (dir) => dirExists(path.join(entrypoint.root.dir, dir)))); |
+ |
+ // TODO(rnystrom): Hackish. Assumes there will only be one or two |
+ // default sources. That's true for pub build and serve, but isn't as |
+ // general as it could be. |
+ if (sourceDirectories.isEmpty) { |
+ var defaults; |
+ if (defaultSourceDirectories.length == 1) { |
+ defaults = 'a "${defaultSourceDirectories.first}" directory'; |
+ } else { |
+ defaults = '"${defaultSourceDirectories[0]}" and/or ' |
+ '"${defaultSourceDirectories[1]}" directories'; |
+ } |
+ |
+ dataError("Your package must have $defaults,\n" |
+ "or you must specify the source directories."); |
+ } |
+ } |
+ |
+ /// Converts a list of [directoryNames] to a sentence. |
+ /// |
+ /// After the list of directories, [singularVerb] will be used if there is |
+ /// only one directory and [pluralVerb] will be used if there are more than |
+ /// one. Then [suffix] is added to the end of the sentence, and, finally, a |
+ /// period is added. |
+ String _directorySentence(Iterable<String> directoryNames, |
+ String singularVerb, String pluralVerb, String suffix) { |
+ var directories = pluralize('Directory', directoryNames.length, |
+ plural: 'Directories'); |
+ var names = toSentence(directoryNames.map((dir) => '"$dir"')); |
+ var verb = pluralize(singularVerb, directoryNames.length, |
+ plural: pluralVerb); |
+ |
+ var result = "$directories $names $verb"; |
+ if (suffix != null) result += " $suffix"; |
+ result += "."; |
+ |
+ return result; |
+ } |
+} |