Chromium Code Reviews| Index: sdk/lib/_internal/pub/bin/pub.dart |
| diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart |
| index a589dcc8403a9ac31593a593ad2afb4545c1f627..d0bfcba3e2f758e9535303f86cce05ac580d14bb 100644 |
| --- a/sdk/lib/_internal/pub/bin/pub.dart |
| +++ b/sdk/lib/_internal/pub/bin/pub.dart |
| @@ -7,9 +7,11 @@ import 'dart:io'; |
| import 'package:args/args.dart'; |
| import 'package:path/path.dart' as path; |
| +import 'package:stack_trace/stack_trace.dart'; |
| import '../lib/src/command.dart'; |
| import '../lib/src/exit_codes.dart' as exit_codes; |
| +import '../lib/src/http.dart'; |
| import '../lib/src/io.dart'; |
| import '../lib/src/log.dart' as log; |
| import '../lib/src/sdk.dart' as sdk; |
| @@ -38,18 +40,6 @@ void main(List<String> arguments) { |
| return; |
| } |
| - if (options.command == null) { |
| - if (options.rest.isEmpty) { |
| - // No command was chosen. |
| - PubCommand.printGlobalUsage(); |
| - } else { |
| - log.error('Could not find a command named "${options.rest[0]}".'); |
| - log.error('Run "pub help" to see available commands.'); |
| - flushThenExit(exit_codes.USAGE); |
| - } |
| - return; |
| - } |
| - |
| if (options['trace']) { |
| log.recordTranscript(); |
| } |
| @@ -81,8 +71,130 @@ void main(List<String> arguments) { |
| cacheDir = '${Platform.environment['HOME']}/.pub-cache'; |
| } |
| - validatePlatform().then((_) { |
| - PubCommand.commands[options.command.name].run(cacheDir, options, arguments); |
| + validatePlatform().then((_) => runPub(cacheDir, options, arguments)); |
| +} |
| + |
| +/// Runs the appropriate pub command parsed to [options] from [arguments] using |
|
nweiz
2014/02/04 01:24:29
I'm not sure what "parsed to [options] from [argum
Bob Nystrom
2014/02/06 00:06:31
Reworded.
|
| +/// the system cache in [cacheDir]. |
| +/// |
| +/// Handles and correctly reports any errors that occur while running. |
| +void runPub(String cacheDir, ArgResults options, List<String> arguments) { |
| + handleError(error, Chain chain) { |
|
nweiz
2014/02/04 01:24:29
I don't like how this is a separate named function
Bob Nystrom
2014/02/06 00:06:31
Done.
|
| + // This is basically the top-level exception handler so that we don't |
| + // spew a stack trace on our users. |
| + var message; |
| + |
| + log.error(getErrorMessage(error)); |
| + log.fine("Exception type: ${error.runtimeType}"); |
| + |
| + if (options['trace'] || !isUserFacingException(error)) { |
| + log.error(chain.terse); |
| + } else { |
| + log.fine(chain.terse); |
| + } |
| + |
| + if (error is ApplicationException && error.innerError != null) { |
| + var message = "Wrapped exception: ${error.innerError}"; |
| + if (error.innerTrace != null) message = "$message\n${error.innerTrace}"; |
| + log.fine(message); |
| + } |
| + |
| + if (options['trace']) { |
| + log.dumpTranscript(); |
| + } else if (!isUserFacingException(error)) { |
| + log.error(""" |
| +This is an unexpected error. Please run |
| + |
| + pub --trace ${arguments.map((arg) => "'$arg'").join(' ')} |
| + |
| +and include the results in a bug report on http://dartbug.com/new. |
| +"""); |
| + } |
| + |
| + return flushThenExit(chooseExitCode(error)); |
| + } |
| + |
| + var captureStackChains = |
| + options['trace'] || |
| + options['verbose'] || |
| + options['verbosity'] == 'all'; |
| + |
| + captureErrors(() { |
| + return invokeCommand(cacheDir, options); |
|
nweiz
2014/02/04 01:24:29
Nit: =>
Bob Nystrom
2014/02/06 00:06:31
Done.
|
| + }, captureStackChains: captureStackChains).catchError(handleError) |
| + .then((_) { |
| + // Explicitly exit on success to ensure that any dangling dart:io handles |
| + // don't cause the process to never terminate. |
| + return flushThenExit(exit_codes.SUCCESS); |
| + }); |
| +} |
| + |
| +/// Returns the appropriate exit code for [exception], falling back on 1 if no |
| +/// appropriate exit code could be found. |
| +int chooseExitCode(exception) { |
| + if (exception is HttpException || exception is HttpException || |
| + exception is SocketException || exception is PubHttpException) { |
| + return exit_codes.UNAVAILABLE; |
| + } else if (exception is FormatException) { |
| + return exit_codes.DATA; |
| + } else if (exception is UsageException) { |
| + return exit_codes.USAGE; |
| + } else { |
| + return 1; |
| + } |
| +} |
| + |
| +/// Walks the command tree and runs the selected pub command. |
| +Future invokeCommand(String cacheDir, ArgResults mainOptions) { |
| + var commands = PubCommand.mainCommands; |
| + var command; |
| + var commandString = "pub"; |
| + var options = mainOptions; |
| + |
| + while (commands.isNotEmpty) { |
| + if (options.command == null) { |
| + if (options.rest.isEmpty) { |
| + if (command == null) { |
| + // No top-level command was chosen. |
| + PubCommand.printGlobalUsage(); |
| + return null; |
|
nweiz
2014/02/04 01:24:29
I know it works in this case, but I don't like ret
Bob Nystrom
2014/02/06 00:06:31
Done.
|
| + } |
| + |
| + command.usageError('Missing subcommand for "$commandString".'); |
| + } else { |
| + if (command == null) { |
| + PubCommand.commandUsageError(commands, |
| + 'Could not find a command named "${options.rest[0]}".'); |
| + } |
| + |
| + command.usageError( |
| + 'Could not find a subcommand named "${options.rest[0]}" ' |
| + 'for "$commandString".'); |
|
nweiz
2014/02/04 01:24:29
Nit: when writing multiline strings like this, I l
Bob Nystrom
2014/02/06 00:06:31
Moved the first line up. I think that makes it con
|
| + } |
| + } |
| + |
| + // Step into the command. |
| + options = options.command; |
| + command = commands[options.name]; |
| + commands = command.subcommands; |
| + commandString += " ${options.name}"; |
| + |
| + if (options['help']) { |
| + command.printUsage(); |
| + return null; |
| + } |
| + } |
| + |
| + // Make sure there aren't unexpected arguments. |
| + if (!command.takesArguments && options.rest.isNotEmpty) { |
| + command.usageError( |
| + 'Command "${options.name}" does not take any arguments.'); |
| + } |
| + |
| + return syncFuture(() { |
| + return command.run(cacheDir, options); |
| + }).whenComplete(() { |
| + command.cache.deleteTempDir(); |
| }); |
| } |