Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1302)

Side by Side Diff: sdk/lib/_internal/pub/lib/src/command.dart

Issue 805393002: Update pub to use the new command runner API in args. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/_internal/pub/bin/pub.dart ('k') | sdk/lib/_internal/pub/lib/src/command/barback.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 library pub.command; 5 library pub.command;
6 6
7 import 'dart:async';
8 import 'dart:math' as math;
9
10 import 'package:args/args.dart'; 7 import 'package:args/args.dart';
8 import 'package:args/command_runner.dart';
11 import 'package:path/path.dart' as path; 9 import 'package:path/path.dart' as path;
12 10
13 import 'command/build.dart';
14 import 'command/cache.dart';
15 import 'command/deps.dart';
16 import 'command/downgrade.dart';
17 import 'command/get.dart';
18 import 'command/global.dart';
19 import 'command/help.dart';
20 import 'command/lish.dart';
21 import 'command/list_package_dirs.dart';
22 import 'command/run.dart';
23 import 'command/serve.dart';
24 import 'command/upgrade.dart';
25 import 'command/uploader.dart';
26 import 'command/version.dart';
27 import 'entrypoint.dart'; 11 import 'entrypoint.dart';
28 import 'exceptions.dart';
29 import 'log.dart' as log; 12 import 'log.dart' as log;
30 import 'global_packages.dart'; 13 import 'global_packages.dart';
31 import 'system_cache.dart'; 14 import 'system_cache.dart';
32 import 'utils.dart';
33 15
34 /// The base class for commands for the pub executable. 16 /// The base class for commands for the pub executable.
35 /// 17 ///
36 /// A command may either be a "leaf" command or it may be a parent for a set 18 /// A command may either be a "leaf" command or it may be a parent for a set
37 /// of subcommands. Only leaf commands are ever actually invoked. If a command 19 /// of subcommands. Only leaf commands are ever actually invoked. If a command
38 /// has subcommands, then one of those must always be chosen. 20 /// has subcommands, then one of those must always be chosen.
39 abstract class PubCommand { 21 abstract class PubCommand extends Command {
40 /// The commands that pub understands. 22 SystemCache get cache {
41 static final Map<String, PubCommand> mainCommands = _initCommands(); 23 if (_cache == null) {
42 24 _cache = new SystemCache.withSources(isOffline: isOffline);
43 /// The top-level [ArgParser] used to parse the pub command line. 25 }
44 static final pubArgParser = _initArgParser(); 26 return _cache;
45
46 /// Displays usage information for the app.
47 static void printGlobalUsage() {
48 // Build up a buffer so it shows up as a single log entry.
49 var buffer = new StringBuffer();
50 buffer.writeln('Pub is a package manager for Dart.');
51 buffer.writeln();
52 buffer.writeln('Usage: pub <command> [arguments]');
53 buffer.writeln();
54 buffer.writeln('Global options:');
55 buffer.writeln(pubArgParser.getUsage());
56 buffer.writeln();
57 buffer.write(_listCommands(mainCommands));
58 buffer.writeln();
59 buffer.writeln(
60 'Run "pub help [command]" for more information about a command.');
61 buffer.writeln(
62 'See http://dartlang.org/tools/pub for detailed documentation.');
63
64 log.message(buffer);
65 } 27 }
66
67 /// Fails with a usage error [message] when trying to select from one of
68 /// [commands].
69 static void usageErrorWithCommands(Map<String, PubCommand> commands,
70 String message) {
71 throw new UsageException(message, _listCommands(commands));
72 }
73
74 /// Writes [commands] in a nicely formatted list to [buffer].
75 static String _listCommands(Map<String, PubCommand> commands) {
76 // If there are no subcommands, do nothing.
77 if (commands.isEmpty) return "";
78
79 // Don't include aliases.
80 var names = commands.keys
81 .where((name) => !commands[name].aliases.contains(name));
82
83 // Filter out hidden ones, unless they are all hidden.
84 var visible = names.where((name) => !commands[name].hidden);
85 if (visible.isNotEmpty) names = visible;
86
87 // Show the commands alphabetically.
88 names = ordered(names);
89 var length = names.map((name) => name.length).reduce(math.max);
90 var isSubcommand = commands != mainCommands;
91
92 var buffer = new StringBuffer();
93 buffer.writeln('Available ${isSubcommand ? "sub" : ""}commands:');
94 for (var name in names) {
95 buffer.writeln(' ${padRight(name, length)} '
96 '${commands[name].description.split("\n").first}');
97 }
98
99 return buffer.toString();
100 }
101
102 SystemCache get cache => _cache;
103 SystemCache _cache; 28 SystemCache _cache;
104 29
105 GlobalPackages get globals => _globals; 30 GlobalPackages get globals {
31 if (_globals == null) {
32 _globals = new GlobalPackages(cache);
33 }
34 return _globals;
35 }
106 GlobalPackages _globals; 36 GlobalPackages _globals;
107 37
108 /// The parsed options for the pub executable.
109 ArgResults get globalOptions => _globalOptions;
110 ArgResults _globalOptions;
111
112 /// The parsed options for this command.
113 ArgResults get commandOptions => _commandOptions;
114 ArgResults _commandOptions;
115
116 /// Gets the [Entrypoint] package for the current working directory. 38 /// Gets the [Entrypoint] package for the current working directory.
117 /// 39 ///
118 /// This will load the pubspec and fail with an error if the current directory 40 /// This will load the pubspec and fail with an error if the current directory
119 /// is not a package. 41 /// is not a package.
120 Entrypoint get entrypoint { 42 Entrypoint get entrypoint {
121 // Lazy load it. 43 // Lazy load it.
122 if (_entrypoint == null) { 44 if (_entrypoint == null) {
123 _entrypoint = new Entrypoint(path.current, _cache, 45 _entrypoint = new Entrypoint(path.current, cache,
124 packageSymlinks: globalOptions['package-symlinks']); 46 packageSymlinks: globalResults['package-symlinks']);
125 } 47 }
126 return _entrypoint; 48 return _entrypoint;
127 } 49 }
128
129 Entrypoint _entrypoint; 50 Entrypoint _entrypoint;
130 51
131 /// A one-line description of this command.
132 String get description;
133
134 /// If the command is undocumented and should not appear in command listings,
135 /// this will be `true`.
136 bool get hidden {
137 // Leaf commands are visible by default.
138 if (subcommands.isEmpty) return false;
139
140 // Otherwise, a command is hidden if all of its subcommands are.
141 return subcommands.values.every((subcommand) => subcommand.hidden);
142 }
143
144 /// How to invoke this command (e.g. `"pub get [package]"`).
145 String get usage;
146
147 /// The URL for web documentation for this command. 52 /// The URL for web documentation for this command.
148 String get docUrl => null; 53 String get docUrl => null;
149 54
150 /// Whether or not this command takes arguments in addition to options.
151 ///
152 /// If false, pub will exit with an error if arguments are provided. This
153 /// only needs to be set in leaf commands.
154 bool get takesArguments => false;
155
156 /// Override this and return `false` to disallow trailing options from being 55 /// Override this and return `false` to disallow trailing options from being
157 /// parsed after a non-option argument is parsed. 56 /// parsed after a non-option argument is parsed.
158 bool get allowTrailingOptions => true; 57 bool get allowTrailingOptions => true;
159 58
160 /// Alternate names for this command. 59 ArgParser get argParser {
161 /// 60 // Lazily initialize the parser because the superclass constructor requires
162 /// These names won't be used in the documentation, but they will work when 61 // it but we want to initialize it based on [allowTrailingOptions].
163 /// invoked on the command line. 62 if (_argParser == null) {
164 final aliases = const <String>[]; 63 _argParser = new ArgParser(allowTrailingOptions: allowTrailingOptions);
165 64 }
166 /// The [ArgParser] for this command. 65 return _argParser;
167 ArgParser get commandParser => _commandParser; 66 }
168 ArgParser _commandParser; 67 ArgParser _argParser;
169
170 /// Subcommands exposed by this command.
171 ///
172 /// If empty, then this command has no subcommands. Otherwise, a subcommand
173 /// must be specified by the user. In that case, this command's [onRun] will
174 /// not be called and the subcommand's will.
175 final subcommands = <String, PubCommand>{};
176 68
177 /// Override this to use offline-only sources instead of hitting the network. 69 /// Override this to use offline-only sources instead of hitting the network.
178 /// 70 ///
179 /// This will only be called before the [SystemCache] is created. After that, 71 /// This will only be called before the [SystemCache] is created. After that,
180 /// it has no effect. This only needs to be set in leaf commands. 72 /// it has no effect. This only needs to be set in leaf commands.
181 bool get isOffline => false; 73 bool get isOffline => false;
182 74
183 PubCommand() { 75 String get usageFooter {
184 _commandParser = new ArgParser(allowTrailingOptions: allowTrailingOptions); 76 if (docUrl == null) return null;
185 77 return "See $docUrl for detailed documentation.";
186 // Allow "--help" after a command to get command help.
187 commandParser.addFlag('help', abbr: 'h', negatable: false,
188 help: 'Print usage information for this command.');
189 } 78 }
190 79
191 /// Runs this command using a system cache at [cacheDir] with [globalOptions] 80 void printUsage() {
192 /// and [options]. 81 log.message(usage);
193 Future run(String cacheDir, ArgResults globalOptions, ArgResults options) {
194 _globalOptions = globalOptions;
195 _commandOptions = options;
196
197 _cache = new SystemCache.withSources(cacheDir, isOffline: isOffline);
198 _globals = new GlobalPackages(_cache);
199
200 return new Future.sync(onRun);
201 }
202
203 /// Override this to perform the specific command.
204 ///
205 /// Return a future that completes when the command is done or fails if the
206 /// command fails. If the command is synchronous, it may return `null`. Only
207 /// leaf command should override this.
208 Future onRun() {
209 // Leaf commands should override this and non-leaf commands should never
210 // call it.
211 assert(false);
212 return null;
213 }
214
215 /// Displays usage information for this command.
216 ///
217 /// If [description] is omitted, defaults to the command's description.
218 void printUsage([String description]) {
219 if (description == null) description = this.description;
220 log.message('$description\n\n${_getUsage()}');
221 }
222
223 /// Throw a [UsageException] for a usage error of this command with
224 /// [message].
225 void usageError(String message) {
226 throw new UsageException(message, _getUsage());
227 } 82 }
228 83
229 /// Parses a user-supplied integer [intString] named [name]. 84 /// Parses a user-supplied integer [intString] named [name].
230 /// 85 ///
231 /// If the parsing fails, prints a usage message and exits. 86 /// If the parsing fails, prints a usage message and exits.
232 int parseInt(String intString, String name) { 87 int parseInt(String intString, String name) {
233 try { 88 try {
234 return int.parse(intString); 89 return int.parse(intString);
235 } on FormatException catch (_) { 90 } on FormatException catch (_) {
236 usageError('Could not parse $name "$intString".'); 91 usageException('Could not parse $name "$intString".');
237 } 92 }
238 } 93 }
239
240 /// Generates a string of usage information for this command.
241 String _getUsage() {
242 var buffer = new StringBuffer();
243 buffer.write('Usage: $usage');
244
245 var commandUsage = commandParser.getUsage();
246 if (!commandUsage.isEmpty) {
247 buffer.writeln();
248 buffer.writeln(commandUsage);
249 }
250
251 if (subcommands.isNotEmpty) {
252 buffer.writeln();
253 buffer.write(_listCommands(subcommands));
254 }
255
256 buffer.writeln();
257 buffer.writeln('Run "pub help" to see global options.');
258 if (docUrl != null) {
259 buffer.writeln("See $docUrl for detailed documentation.");
260 }
261
262 return buffer.toString();
263 }
264 } 94 }
265
266 _initCommands() {
267 var commands = {
268 'build': new BuildCommand(),
269 'cache': new CacheCommand(),
270 'deps': new DepsCommand(),
271 'downgrade': new DowngradeCommand(),
272 'global': new GlobalCommand(),
273 'get': new GetCommand(),
274 'help': new HelpCommand(),
275 'list-package-dirs': new ListPackageDirsCommand(),
276 'publish': new LishCommand(),
277 'run': new RunCommand(),
278 'serve': new ServeCommand(),
279 'upgrade': new UpgradeCommand(),
280 'uploader': new UploaderCommand(),
281 'version': new VersionCommand()
282 };
283
284 for (var command in commands.values.toList()) {
285 for (var alias in command.aliases) {
286 commands[alias] = command;
287 }
288 }
289
290 return commands;
291 }
292
293 /// Creates the top-level [ArgParser] used to parse the pub command line.
294 ArgParser _initArgParser() {
295 var argParser = new ArgParser(allowTrailingOptions: true);
296
297 // Add the global options.
298 argParser.addFlag('help', abbr: 'h', negatable: false,
299 help: 'Print this usage information.');
300 argParser.addFlag('version', negatable: false,
301 help: 'Print pub version.');
302 argParser.addFlag('trace',
303 help: 'Print debugging information when an error occurs.');
304 argParser.addOption('verbosity',
305 help: 'Control output verbosity.',
306 allowed: ['normal', 'io', 'solver', 'all'],
307 allowedHelp: {
308 'normal': 'Show errors, warnings, and user messages.',
309 'io': 'Also show IO operations.',
310 'solver': 'Show steps during version resolution.',
311 'all': 'Show all output including internal tracing messages.'
312 });
313 argParser.addFlag('verbose', abbr: 'v', negatable: false,
314 help: 'Shortcut for "--verbosity=all".');
315 argParser.addFlag('with-prejudice', hide: !isAprilFools, negatable: false,
316 help: 'Execute commands with prejudice.');
317 argParser.addFlag('package-symlinks', hide: true, negatable: true,
318 defaultsTo: true);
319
320 // Register the commands.
321 PubCommand.mainCommands.forEach((name, command) {
322 _registerCommand(name, command, argParser);
323 });
324
325 return argParser;
326 }
327
328 /// Registers a [command] with [name] on [parser].
329 void _registerCommand(String name, PubCommand command, ArgParser parser) {
330 parser.addCommand(name, command.commandParser);
331
332 // Recursively wire up any subcommands.
333 command.subcommands.forEach((name, subcommand) {
334 _registerCommand(name, subcommand, command.commandParser);
335 });
336 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/pub/bin/pub.dart ('k') | sdk/lib/_internal/pub/lib/src/command/barback.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698