Index: sdk/lib/_internal/pub/lib/src/command.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart |
index 0c92abda4ea79bf6f6470adc3bb8b093144e0920..3a1647154f13554a9beef16b98a1e54cae5bd0de 100644 |
--- a/sdk/lib/_internal/pub/lib/src/command.dart |
+++ b/sdk/lib/_internal/pub/lib/src/command.dart |
@@ -4,115 +4,37 @@ |
library pub.command; |
-import 'dart:async'; |
-import 'dart:math' as math; |
- |
import 'package:args/args.dart'; |
+import 'package:args/command_runner.dart'; |
import 'package:path/path.dart' as path; |
-import 'command/build.dart'; |
-import 'command/cache.dart'; |
-import 'command/deps.dart'; |
-import 'command/downgrade.dart'; |
-import 'command/get.dart'; |
-import 'command/global.dart'; |
-import 'command/help.dart'; |
-import 'command/lish.dart'; |
-import 'command/list_package_dirs.dart'; |
-import 'command/run.dart'; |
-import 'command/serve.dart'; |
-import 'command/upgrade.dart'; |
-import 'command/uploader.dart'; |
-import 'command/version.dart'; |
import 'entrypoint.dart'; |
-import 'exceptions.dart'; |
import 'log.dart' as log; |
import 'global_packages.dart'; |
import 'system_cache.dart'; |
-import 'utils.dart'; |
/// The base class for commands for the pub executable. |
/// |
/// A command may either be a "leaf" command or it may be a parent for a set |
/// of subcommands. Only leaf commands are ever actually invoked. If a command |
/// has subcommands, then one of those must always be chosen. |
-abstract class PubCommand { |
- /// The commands that pub understands. |
- static final Map<String, PubCommand> mainCommands = _initCommands(); |
- |
- /// The top-level [ArgParser] used to parse the pub command line. |
- static final pubArgParser = _initArgParser(); |
- |
- /// Displays usage information for the app. |
- static void printGlobalUsage() { |
- // Build up a buffer so it shows up as a single log entry. |
- var buffer = new StringBuffer(); |
- buffer.writeln('Pub is a package manager for Dart.'); |
- buffer.writeln(); |
- buffer.writeln('Usage: pub <command> [arguments]'); |
- buffer.writeln(); |
- buffer.writeln('Global options:'); |
- buffer.writeln(pubArgParser.getUsage()); |
- buffer.writeln(); |
- buffer.write(_listCommands(mainCommands)); |
- buffer.writeln(); |
- buffer.writeln( |
- 'Run "pub help [command]" for more information about a command.'); |
- buffer.writeln( |
- 'See http://dartlang.org/tools/pub for detailed documentation.'); |
- |
- log.message(buffer); |
- } |
- |
- /// Fails with a usage error [message] when trying to select from one of |
- /// [commands]. |
- static void usageErrorWithCommands(Map<String, PubCommand> commands, |
- String message) { |
- throw new UsageException(message, _listCommands(commands)); |
- } |
- |
- /// Writes [commands] in a nicely formatted list to [buffer]. |
- static String _listCommands(Map<String, PubCommand> commands) { |
- // If there are no subcommands, do nothing. |
- if (commands.isEmpty) return ""; |
- |
- // Don't include aliases. |
- var names = commands.keys |
- .where((name) => !commands[name].aliases.contains(name)); |
- |
- // Filter out hidden ones, unless they are all hidden. |
- var visible = names.where((name) => !commands[name].hidden); |
- if (visible.isNotEmpty) names = visible; |
- |
- // Show the commands alphabetically. |
- names = ordered(names); |
- var length = names.map((name) => name.length).reduce(math.max); |
- var isSubcommand = commands != mainCommands; |
- |
- var buffer = new StringBuffer(); |
- buffer.writeln('Available ${isSubcommand ? "sub" : ""}commands:'); |
- for (var name in names) { |
- buffer.writeln(' ${padRight(name, length)} ' |
- '${commands[name].description.split("\n").first}'); |
+abstract class PubCommand extends Command { |
+ SystemCache get cache { |
+ if (_cache == null) { |
+ _cache = new SystemCache.withSources(isOffline: isOffline); |
} |
- |
- return buffer.toString(); |
+ return _cache; |
} |
- |
- SystemCache get cache => _cache; |
SystemCache _cache; |
- GlobalPackages get globals => _globals; |
+ GlobalPackages get globals { |
+ if (_globals == null) { |
+ _globals = new GlobalPackages(cache); |
+ } |
+ return _globals; |
+ } |
GlobalPackages _globals; |
- /// The parsed options for the pub executable. |
- ArgResults get globalOptions => _globalOptions; |
- ArgResults _globalOptions; |
- |
- /// The parsed options for this command. |
- ArgResults get commandOptions => _commandOptions; |
- ArgResults _commandOptions; |
- |
/// Gets the [Entrypoint] package for the current working directory. |
/// |
/// This will load the pubspec and fail with an error if the current directory |
@@ -120,59 +42,29 @@ abstract class PubCommand { |
Entrypoint get entrypoint { |
// Lazy load it. |
if (_entrypoint == null) { |
- _entrypoint = new Entrypoint(path.current, _cache, |
- packageSymlinks: globalOptions['package-symlinks']); |
+ _entrypoint = new Entrypoint(path.current, cache, |
+ packageSymlinks: globalResults['package-symlinks']); |
} |
return _entrypoint; |
} |
- |
Entrypoint _entrypoint; |
- /// A one-line description of this command. |
- String get description; |
- |
- /// If the command is undocumented and should not appear in command listings, |
- /// this will be `true`. |
- bool get hidden { |
- // Leaf commands are visible by default. |
- if (subcommands.isEmpty) return false; |
- |
- // Otherwise, a command is hidden if all of its subcommands are. |
- return subcommands.values.every((subcommand) => subcommand.hidden); |
- } |
- |
- /// How to invoke this command (e.g. `"pub get [package]"`). |
- String get usage; |
- |
/// The URL for web documentation for this command. |
String get docUrl => null; |
- /// Whether or not this command takes arguments in addition to options. |
- /// |
- /// If false, pub will exit with an error if arguments are provided. This |
- /// only needs to be set in leaf commands. |
- bool get takesArguments => false; |
- |
/// Override this and return `false` to disallow trailing options from being |
/// parsed after a non-option argument is parsed. |
bool get allowTrailingOptions => true; |
- /// Alternate names for this command. |
- /// |
- /// These names won't be used in the documentation, but they will work when |
- /// invoked on the command line. |
- final aliases = const <String>[]; |
- |
- /// The [ArgParser] for this command. |
- ArgParser get commandParser => _commandParser; |
- ArgParser _commandParser; |
- |
- /// Subcommands exposed by this command. |
- /// |
- /// If empty, then this command has no subcommands. Otherwise, a subcommand |
- /// must be specified by the user. In that case, this command's [onRun] will |
- /// not be called and the subcommand's will. |
- final subcommands = <String, PubCommand>{}; |
+ ArgParser get argParser { |
+ // Lazily initialize the parser because the superclass constructor requires |
+ // it but we want to initialize it based on [allowTrailingOptions]. |
+ if (_argParser == null) { |
+ _argParser = new ArgParser(allowTrailingOptions: allowTrailingOptions); |
+ } |
+ return _argParser; |
+ } |
+ ArgParser _argParser; |
/// Override this to use offline-only sources instead of hitting the network. |
/// |
@@ -180,50 +72,13 @@ abstract class PubCommand { |
/// it has no effect. This only needs to be set in leaf commands. |
bool get isOffline => false; |
- PubCommand() { |
- _commandParser = new ArgParser(allowTrailingOptions: allowTrailingOptions); |
- |
- // Allow "--help" after a command to get command help. |
- commandParser.addFlag('help', abbr: 'h', negatable: false, |
- help: 'Print usage information for this command.'); |
+ String get usageFooter { |
+ if (docUrl == null) return null; |
+ return "See $docUrl for detailed documentation."; |
} |
- /// Runs this command using a system cache at [cacheDir] with [globalOptions] |
- /// and [options]. |
- Future run(String cacheDir, ArgResults globalOptions, ArgResults options) { |
- _globalOptions = globalOptions; |
- _commandOptions = options; |
- |
- _cache = new SystemCache.withSources(cacheDir, isOffline: isOffline); |
- _globals = new GlobalPackages(_cache); |
- |
- return new Future.sync(onRun); |
- } |
- |
- /// Override this to perform the specific command. |
- /// |
- /// Return a future that completes when the command is done or fails if the |
- /// command fails. If the command is synchronous, it may return `null`. Only |
- /// leaf command should override this. |
- Future onRun() { |
- // Leaf commands should override this and non-leaf commands should never |
- // call it. |
- assert(false); |
- return null; |
- } |
- |
- /// Displays usage information for this command. |
- /// |
- /// If [description] is omitted, defaults to the command's description. |
- void printUsage([String description]) { |
- if (description == null) description = this.description; |
- log.message('$description\n\n${_getUsage()}'); |
- } |
- |
- /// Throw a [UsageException] for a usage error of this command with |
- /// [message]. |
- void usageError(String message) { |
- throw new UsageException(message, _getUsage()); |
+ void printUsage() { |
+ log.message(usage); |
} |
/// Parses a user-supplied integer [intString] named [name]. |
@@ -233,104 +88,7 @@ abstract class PubCommand { |
try { |
return int.parse(intString); |
} on FormatException catch (_) { |
- usageError('Could not parse $name "$intString".'); |
+ usageException('Could not parse $name "$intString".'); |
} |
} |
- |
- /// Generates a string of usage information for this command. |
- String _getUsage() { |
- var buffer = new StringBuffer(); |
- buffer.write('Usage: $usage'); |
- |
- var commandUsage = commandParser.getUsage(); |
- if (!commandUsage.isEmpty) { |
- buffer.writeln(); |
- buffer.writeln(commandUsage); |
- } |
- |
- if (subcommands.isNotEmpty) { |
- buffer.writeln(); |
- buffer.write(_listCommands(subcommands)); |
- } |
- |
- buffer.writeln(); |
- buffer.writeln('Run "pub help" to see global options.'); |
- if (docUrl != null) { |
- buffer.writeln("See $docUrl for detailed documentation."); |
- } |
- |
- return buffer.toString(); |
- } |
-} |
- |
-_initCommands() { |
- var commands = { |
- 'build': new BuildCommand(), |
- 'cache': new CacheCommand(), |
- 'deps': new DepsCommand(), |
- 'downgrade': new DowngradeCommand(), |
- 'global': new GlobalCommand(), |
- 'get': new GetCommand(), |
- 'help': new HelpCommand(), |
- 'list-package-dirs': new ListPackageDirsCommand(), |
- 'publish': new LishCommand(), |
- 'run': new RunCommand(), |
- 'serve': new ServeCommand(), |
- 'upgrade': new UpgradeCommand(), |
- 'uploader': new UploaderCommand(), |
- 'version': new VersionCommand() |
- }; |
- |
- for (var command in commands.values.toList()) { |
- for (var alias in command.aliases) { |
- commands[alias] = command; |
- } |
- } |
- |
- return commands; |
-} |
- |
-/// Creates the top-level [ArgParser] used to parse the pub command line. |
-ArgParser _initArgParser() { |
- var argParser = new ArgParser(allowTrailingOptions: true); |
- |
- // Add the global options. |
- argParser.addFlag('help', abbr: 'h', negatable: false, |
- help: 'Print this usage information.'); |
- argParser.addFlag('version', negatable: false, |
- help: 'Print pub version.'); |
- argParser.addFlag('trace', |
- help: 'Print debugging information when an error occurs.'); |
- argParser.addOption('verbosity', |
- help: 'Control output verbosity.', |
- allowed: ['normal', 'io', 'solver', 'all'], |
- allowedHelp: { |
- 'normal': 'Show errors, warnings, and user messages.', |
- 'io': 'Also show IO operations.', |
- 'solver': 'Show steps during version resolution.', |
- 'all': 'Show all output including internal tracing messages.' |
- }); |
- argParser.addFlag('verbose', abbr: 'v', negatable: false, |
- help: 'Shortcut for "--verbosity=all".'); |
- argParser.addFlag('with-prejudice', hide: !isAprilFools, negatable: false, |
- help: 'Execute commands with prejudice.'); |
- argParser.addFlag('package-symlinks', hide: true, negatable: true, |
- defaultsTo: true); |
- |
- // Register the commands. |
- PubCommand.mainCommands.forEach((name, command) { |
- _registerCommand(name, command, argParser); |
- }); |
- |
- return argParser; |
-} |
- |
-/// Registers a [command] with [name] on [parser]. |
-void _registerCommand(String name, PubCommand command, ArgParser parser) { |
- parser.addCommand(name, command.commandParser); |
- |
- // Recursively wire up any subcommands. |
- command.subcommands.forEach((name, subcommand) { |
- _registerCommand(name, subcommand, command.commandParser); |
- }); |
} |