Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:io'; | 6 import 'dart:io'; |
| 7 | 7 |
| 8 import 'package:args/args.dart'; | 8 import 'package:args/args.dart'; |
| 9 import 'package:path/path.dart' as path; | 9 import 'package:path/path.dart' as path; |
| 10 import 'package:stack_trace/stack_trace.dart'; | |
| 10 | 11 |
| 11 import '../lib/src/command.dart'; | 12 import '../lib/src/command.dart'; |
| 12 import '../lib/src/exit_codes.dart' as exit_codes; | 13 import '../lib/src/exit_codes.dart' as exit_codes; |
| 14 import '../lib/src/http.dart'; | |
| 13 import '../lib/src/io.dart'; | 15 import '../lib/src/io.dart'; |
| 14 import '../lib/src/log.dart' as log; | 16 import '../lib/src/log.dart' as log; |
| 15 import '../lib/src/sdk.dart' as sdk; | 17 import '../lib/src/sdk.dart' as sdk; |
| 16 import '../lib/src/utils.dart'; | 18 import '../lib/src/utils.dart'; |
| 17 | 19 |
| 18 void main(List<String> arguments) { | 20 void main(List<String> arguments) { |
| 19 ArgResults options; | 21 ArgResults options; |
| 20 | 22 |
| 21 try { | 23 try { |
| 22 options = PubCommand.pubArgParser.parse(arguments, | 24 options = PubCommand.pubArgParser.parse(arguments, |
| 23 allowTrailingOptions: true); | 25 allowTrailingOptions: true); |
| 24 } on FormatException catch (e) { | 26 } on FormatException catch (e) { |
| 25 log.error(e.message); | 27 log.error(e.message); |
| 26 log.error('Run "pub help" to see available options.'); | 28 log.error('Run "pub help" to see available options.'); |
| 27 flushThenExit(exit_codes.USAGE); | 29 flushThenExit(exit_codes.USAGE); |
| 28 return; | 30 return; |
| 29 } | 31 } |
| 30 | 32 |
| 31 if (options['version']) { | 33 if (options['version']) { |
| 32 log.message('Pub ${sdk.version}'); | 34 log.message('Pub ${sdk.version}'); |
| 33 return; | 35 return; |
| 34 } | 36 } |
| 35 | 37 |
| 36 if (options['help']) { | 38 if (options['help']) { |
| 37 PubCommand.printGlobalUsage(); | 39 PubCommand.printGlobalUsage(); |
| 38 return; | 40 return; |
| 39 } | 41 } |
| 40 | 42 |
| 41 if (options.command == null) { | |
| 42 if (options.rest.isEmpty) { | |
| 43 // No command was chosen. | |
| 44 PubCommand.printGlobalUsage(); | |
| 45 } else { | |
| 46 log.error('Could not find a command named "${options.rest[0]}".'); | |
| 47 log.error('Run "pub help" to see available commands.'); | |
| 48 flushThenExit(exit_codes.USAGE); | |
| 49 } | |
| 50 return; | |
| 51 } | |
| 52 | |
| 53 if (options['trace']) { | 43 if (options['trace']) { |
| 54 log.recordTranscript(); | 44 log.recordTranscript(); |
| 55 } | 45 } |
| 56 | 46 |
| 57 switch (options['verbosity']) { | 47 switch (options['verbosity']) { |
| 58 case 'normal': log.showNormal(); break; | 48 case 'normal': log.showNormal(); break; |
| 59 case 'io': log.showIO(); break; | 49 case 'io': log.showIO(); break; |
| 60 case 'solver': log.showSolver(); break; | 50 case 'solver': log.showSolver(); break; |
| 61 case 'all': log.showAll(); break; | 51 case 'all': log.showAll(); break; |
| 62 default: | 52 default: |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 74 var cacheDir; | 64 var cacheDir; |
| 75 if (Platform.environment.containsKey('PUB_CACHE')) { | 65 if (Platform.environment.containsKey('PUB_CACHE')) { |
| 76 cacheDir = Platform.environment['PUB_CACHE']; | 66 cacheDir = Platform.environment['PUB_CACHE']; |
| 77 } else if (Platform.operatingSystem == 'windows') { | 67 } else if (Platform.operatingSystem == 'windows') { |
| 78 var appData = Platform.environment['APPDATA']; | 68 var appData = Platform.environment['APPDATA']; |
| 79 cacheDir = path.join(appData, 'Pub', 'Cache'); | 69 cacheDir = path.join(appData, 'Pub', 'Cache'); |
| 80 } else { | 70 } else { |
| 81 cacheDir = '${Platform.environment['HOME']}/.pub-cache'; | 71 cacheDir = '${Platform.environment['HOME']}/.pub-cache'; |
| 82 } | 72 } |
| 83 | 73 |
| 84 validatePlatform().then((_) { | 74 validatePlatform().then((_) => runPub(cacheDir, options, arguments)); |
| 85 PubCommand.commands[options.command.name].run(cacheDir, options, arguments); | 75 } |
| 76 | |
| 77 /// 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.
| |
| 78 /// the system cache in [cacheDir]. | |
| 79 /// | |
| 80 /// Handles and correctly reports any errors that occur while running. | |
| 81 void runPub(String cacheDir, ArgResults options, List<String> arguments) { | |
| 82 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.
| |
| 83 // This is basically the top-level exception handler so that we don't | |
| 84 // spew a stack trace on our users. | |
| 85 var message; | |
| 86 | |
| 87 log.error(getErrorMessage(error)); | |
| 88 log.fine("Exception type: ${error.runtimeType}"); | |
| 89 | |
| 90 if (options['trace'] || !isUserFacingException(error)) { | |
| 91 log.error(chain.terse); | |
| 92 } else { | |
| 93 log.fine(chain.terse); | |
| 94 } | |
| 95 | |
| 96 if (error is ApplicationException && error.innerError != null) { | |
| 97 var message = "Wrapped exception: ${error.innerError}"; | |
| 98 if (error.innerTrace != null) message = "$message\n${error.innerTrace}"; | |
| 99 log.fine(message); | |
| 100 } | |
| 101 | |
| 102 if (options['trace']) { | |
| 103 log.dumpTranscript(); | |
| 104 } else if (!isUserFacingException(error)) { | |
| 105 log.error(""" | |
| 106 This is an unexpected error. Please run | |
| 107 | |
| 108 pub --trace ${arguments.map((arg) => "'$arg'").join(' ')} | |
| 109 | |
| 110 and include the results in a bug report on http://dartbug.com/new. | |
| 111 """); | |
| 112 } | |
| 113 | |
| 114 return flushThenExit(chooseExitCode(error)); | |
| 115 } | |
| 116 | |
| 117 var captureStackChains = | |
| 118 options['trace'] || | |
| 119 options['verbose'] || | |
| 120 options['verbosity'] == 'all'; | |
| 121 | |
| 122 captureErrors(() { | |
| 123 return invokeCommand(cacheDir, options); | |
|
nweiz
2014/02/04 01:24:29
Nit: =>
Bob Nystrom
2014/02/06 00:06:31
Done.
| |
| 124 }, captureStackChains: captureStackChains).catchError(handleError) | |
| 125 .then((_) { | |
| 126 // Explicitly exit on success to ensure that any dangling dart:io handles | |
| 127 // don't cause the process to never terminate. | |
| 128 return flushThenExit(exit_codes.SUCCESS); | |
| 86 }); | 129 }); |
| 87 } | 130 } |
| 88 | 131 |
| 132 /// Returns the appropriate exit code for [exception], falling back on 1 if no | |
| 133 /// appropriate exit code could be found. | |
| 134 int chooseExitCode(exception) { | |
| 135 if (exception is HttpException || exception is HttpException || | |
| 136 exception is SocketException || exception is PubHttpException) { | |
| 137 return exit_codes.UNAVAILABLE; | |
| 138 } else if (exception is FormatException) { | |
| 139 return exit_codes.DATA; | |
| 140 } else if (exception is UsageException) { | |
| 141 return exit_codes.USAGE; | |
| 142 } else { | |
| 143 return 1; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 /// Walks the command tree and runs the selected pub command. | |
| 148 Future invokeCommand(String cacheDir, ArgResults mainOptions) { | |
| 149 var commands = PubCommand.mainCommands; | |
| 150 var command; | |
| 151 var commandString = "pub"; | |
| 152 var options = mainOptions; | |
| 153 | |
| 154 while (commands.isNotEmpty) { | |
| 155 if (options.command == null) { | |
| 156 if (options.rest.isEmpty) { | |
| 157 if (command == null) { | |
| 158 // No top-level command was chosen. | |
| 159 PubCommand.printGlobalUsage(); | |
| 160 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.
| |
| 161 } | |
| 162 | |
| 163 command.usageError('Missing subcommand for "$commandString".'); | |
| 164 } else { | |
| 165 if (command == null) { | |
| 166 PubCommand.commandUsageError(commands, | |
| 167 'Could not find a command named "${options.rest[0]}".'); | |
| 168 } | |
| 169 | |
| 170 command.usageError( | |
| 171 'Could not find a subcommand named "${options.rest[0]}" ' | |
| 172 '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
| |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Step into the command. | |
| 177 options = options.command; | |
| 178 command = commands[options.name]; | |
| 179 commands = command.subcommands; | |
| 180 commandString += " ${options.name}"; | |
| 181 | |
| 182 if (options['help']) { | |
| 183 command.printUsage(); | |
| 184 return null; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 // Make sure there aren't unexpected arguments. | |
| 189 if (!command.takesArguments && options.rest.isNotEmpty) { | |
| 190 command.usageError( | |
| 191 'Command "${options.name}" does not take any arguments.'); | |
| 192 } | |
| 193 | |
| 194 return syncFuture(() { | |
| 195 return command.run(cacheDir, options); | |
| 196 }).whenComplete(() { | |
| 197 command.cache.deleteTempDir(); | |
| 198 }); | |
| 199 } | |
| 200 | |
| 89 /// Checks that pub is running on a supported platform. If it isn't, it prints | 201 /// Checks that pub is running on a supported platform. If it isn't, it prints |
| 90 /// an error message and exits. Completes when the validation is done. | 202 /// an error message and exits. Completes when the validation is done. |
| 91 Future validatePlatform() { | 203 Future validatePlatform() { |
| 92 return syncFuture(() { | 204 return syncFuture(() { |
| 93 if (Platform.operatingSystem != 'windows') return null; | 205 if (Platform.operatingSystem != 'windows') return null; |
| 94 | 206 |
| 95 return runProcess('ver', []).then((result) { | 207 return runProcess('ver', []).then((result) { |
| 96 if (result.stdout.join('\n').contains('XP')) { | 208 if (result.stdout.join('\n').contains('XP')) { |
| 97 log.error('Sorry, but pub is not supported on Windows XP.'); | 209 log.error('Sorry, but pub is not supported on Windows XP.'); |
| 98 return flushThenExit(exit_codes.USAGE); | 210 return flushThenExit(exit_codes.USAGE); |
| 99 } | 211 } |
| 100 }); | 212 }); |
| 101 }); | 213 }); |
| 102 } | 214 } |
| OLD | NEW |