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

Side by Side Diff: utils/pub/pub.dart

Issue 14297021: Move pub into sdk/lib/_internal. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Disallow package: imports of pub. Created 7 years, 8 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 | « utils/pub/path_source.dart ('k') | utils/pub/pubspec.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
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.
4
5 /// The main entrypoint for the pub command line application.
6 library pub;
7
8 import 'dart:async';
9 import 'dart:io';
10 import 'dart:math';
11
12 import 'package:args/args.dart';
13 import 'package:pathos/path.dart' as path;
14
15 import 'command_help.dart';
16 import 'command_install.dart';
17 import 'command_lish.dart';
18 import 'command_update.dart';
19 import 'command_uploader.dart';
20 import 'command_version.dart';
21 import 'command_cache.dart';
22 import 'entrypoint.dart';
23 import 'exit_codes.dart' as exit_codes;
24 import 'http.dart';
25 import 'io.dart';
26 import 'log.dart' as log;
27 import 'package.dart';
28 import 'pubspec.dart';
29 import 'sdk.dart' as sdk;
30 import 'source.dart';
31 import 'source_registry.dart';
32 import 'system_cache.dart';
33 import 'utils.dart';
34 import 'version.dart';
35
36 /// The commands that Pub understands.
37 Map<String, PubCommand> get pubCommands {
38 var commands = {
39 'cache': new CacheCommand(),
40 'help': new HelpCommand(),
41 'install': new InstallCommand(),
42 'publish': new LishCommand(),
43 'update': new UpdateCommand(),
44 'uploader': new UploaderCommand(),
45 'version': new VersionCommand()
46 };
47 for (var command in commands.values.toList()) {
48 for (var alias in command.aliases) {
49 commands[alias] = command;
50 }
51 }
52 return commands;
53 }
54
55 /// The parser for arguments that are global to Pub rather than specific to a
56 /// single command.
57 ArgParser get pubArgParser {
58 var parser = new ArgParser();
59 parser.addFlag('help', abbr: 'h', negatable: false,
60 help: 'Print this usage information.');
61 parser.addFlag('version', negatable: false,
62 help: 'Print pub version.');
63 parser.addFlag('trace',
64 help: 'Print debugging information when an error occurs.');
65 parser.addOption('verbosity',
66 help: 'Control output verbosity.',
67 allowed: ['normal', 'io', 'solver', 'all'],
68 allowedHelp: {
69 'normal': 'Show errors, warnings, and user messages.',
70 'io': 'Also show IO operations.',
71 'solver': 'Show steps during version resolution.',
72 'all': 'Show all output including internal tracing messages.'
73 });
74 parser.addFlag('verbose', abbr: 'v', negatable: false,
75 help: 'Shortcut for "--verbosity=all"');
76 return parser;
77 }
78
79 main() {
80 var globalOptions;
81 try {
82 globalOptions = pubArgParser.parse(new Options().arguments);
83 } on FormatException catch (e) {
84 log.error(e.message);
85 log.error('Run "pub help" to see available options.');
86 exit(exit_codes.USAGE);
87 }
88
89 if (globalOptions['version']) {
90 printVersion();
91 return;
92 }
93
94 if (globalOptions['help'] || globalOptions.rest.isEmpty) {
95 printUsage();
96 return;
97 }
98
99 if (globalOptions['trace']) {
100 log.recordTranscript();
101 }
102
103 switch (globalOptions['verbosity']) {
104 case 'normal': log.showNormal(); break;
105 case 'io': log.showIO(); break;
106 case 'solver': log.showSolver(); break;
107 case 'all': log.showAll(); break;
108 default:
109 // No specific verbosity given, so check for the shortcut.
110 if (globalOptions['verbose']) {
111 log.showAll();
112 } else {
113 log.showNormal();
114 }
115 break;
116 }
117
118 SecureSocket.initialize(database: relativeToPub('resource/certs'));
119
120 var cacheDir;
121 if (Platform.environment.containsKey('PUB_CACHE')) {
122 cacheDir = Platform.environment['PUB_CACHE'];
123 } else if (Platform.operatingSystem == 'windows') {
124 var appData = Platform.environment['APPDATA'];
125 cacheDir = path.join(appData, 'Pub', 'Cache');
126 } else {
127 cacheDir = '${Platform.environment['HOME']}/.pub-cache';
128 }
129
130 validatePlatform().then((_) {
131 var cache = new SystemCache.withSources(cacheDir);
132
133 // Select the command.
134 var command = pubCommands[globalOptions.rest[0]];
135 if (command == null) {
136 log.error('Could not find a command named "${globalOptions.rest[0]}".');
137 log.error('Run "pub help" to see available commands.');
138 exit(exit_codes.USAGE);
139 return;
140 }
141
142 var commandArgs = globalOptions.rest.sublist(1);
143 command.run(cache, globalOptions, commandArgs);
144 });
145 }
146
147 /// Checks that pub is running on a supported platform. If it isn't, it prints
148 /// an error message and exits. Completes when the validation is done.
149 Future validatePlatform() {
150 return new Future.sync(() {
151 if (Platform.operatingSystem != 'windows') return;
152
153 return runProcess('ver', []).then((result) {
154 if (result.stdout.join('\n').contains('XP')) {
155 log.error('Sorry, but pub is not supported on Windows XP.');
156 exit(exit_codes.USAGE);
157 }
158 });
159 });
160 }
161
162 /// Displays usage information for the app.
163 void printUsage([String description = 'Pub is a package manager for Dart.']) {
164 // Build up a buffer so it shows up as a single log entry.
165 var buffer = new StringBuffer();
166 buffer.write(description);
167 buffer.write('\n\n');
168 buffer.write('Usage: pub command [arguments]\n\n');
169 buffer.write('Global options:\n');
170 buffer.write('${pubArgParser.getUsage()}\n\n');
171
172 // Show the commands sorted.
173 buffer.write('Available commands:\n');
174
175 // TODO(rnystrom): A sorted map would be nice.
176 int length = 0;
177 var names = <String>[];
178 for (var command in pubCommands.keys) {
179 // Hide aliases.
180 if (pubCommands[command].aliases.indexOf(command) >= 0) continue;
181 length = max(length, command.length);
182 names.add(command);
183 }
184
185 names.sort((a, b) => a.compareTo(b));
186
187 for (var name in names) {
188 buffer.write(' ${padRight(name, length)} '
189 '${pubCommands[name].description}\n');
190 }
191
192 buffer.write('\n');
193 buffer.write(
194 'Use "pub help [command]" for more information about a command.');
195 log.message(buffer.toString());
196 }
197
198 void printVersion() {
199 log.message('Pub ${sdk.version}');
200 }
201
202 abstract class PubCommand {
203 SystemCache cache;
204 ArgResults globalOptions;
205 ArgResults commandOptions;
206
207 Entrypoint entrypoint;
208
209 /// A one-line description of this command.
210 String get description;
211
212 /// How to invoke this command (e.g. `"pub install [package]"`).
213 String get usage;
214
215 /// Whether or not this command requires [entrypoint] to be defined. If false,
216 /// Pub won't look for a pubspec and [entrypoint] will be null when the
217 /// command runs.
218 final requiresEntrypoint = true;
219
220 /// Alternate names for this command. These names won't be used in the
221 /// documentation, but they will work when invoked on the command line.
222 final aliases = const <String>[];
223
224 /// Override this to define command-specific options. The results will be made
225 /// available in [commandOptions].
226 ArgParser get commandParser => new ArgParser();
227
228 void run(SystemCache cache_, ArgResults globalOptions_,
229 List<String> commandArgs) {
230 cache = cache_;
231 globalOptions = globalOptions_;
232
233 try {
234 commandOptions = commandParser.parse(commandArgs);
235 } on FormatException catch (e) {
236 log.error(e.message);
237 log.error('Use "pub help" for more information.');
238 exit(exit_codes.USAGE);
239 }
240
241 handleError(error) {
242 var trace = getAttachedStackTrace(error);
243
244 // This is basically the top-level exception handler so that we don't
245 // spew a stack trace on our users.
246 var message;
247
248 try {
249 // Most exception types have a "message" property. We prefer this since
250 // it skips the "Exception:", "HttpException:", etc. prefix that calling
251 // toString() adds. But, alas, "message" isn't actually defined in the
252 // base Exception type so there's no easy way to know if it's available
253 // short of a giant pile of type tests for each known exception type.
254 //
255 // So just try it. If it throws, default to toString().
256 message = error.message;
257 } on NoSuchMethodError catch (_) {
258 message = error.toString();
259 }
260
261 log.error(message);
262
263 if (trace != null) {
264 if (globalOptions['trace'] || !isUserFacingException(error)) {
265 log.error(trace);
266 } else {
267 log.fine(trace);
268 }
269 }
270
271 if (globalOptions['trace']) {
272 log.dumpTranscript();
273 } else if (!isUserFacingException(error)) {
274 log.error("""
275 This is an unexpected error. Please run
276
277 pub --trace ${new Options().arguments.map((arg) => "'$arg'").join(' ')}
278
279 and include the results in a bug report on http://dartbug.com/new.
280 """);
281 }
282
283 exit(_chooseExitCode(error));
284 }
285
286 new Future.sync(() {
287 if (requiresEntrypoint) {
288 // TODO(rnystrom): Will eventually need better logic to walk up
289 // subdirectories until we hit one that looks package-like. For now,
290 // just assume the cwd is it.
291 entrypoint = new Entrypoint(path.current, cache);
292 }
293
294 var commandFuture = onRun();
295 if (commandFuture == null) return true;
296
297 return commandFuture;
298 }).whenComplete(() => cache_.deleteTempDir()).catchError((e) {
299 if (e is PubspecNotFoundException && e.name == null) {
300 e = 'Could not find a file named "pubspec.yaml" in the directory '
301 '${path.current}.';
302 } else if (e is PubspecHasNoNameException && e.name == null) {
303 e = 'pubspec.yaml is missing the required "name" field (e.g. "name: '
304 '${path.basename(path.current)}").';
305 }
306
307 handleError(e);
308 }).then((_) {
309 // Explicitly exit on success to ensure that any dangling dart:io handles
310 // don't cause the process to never terminate.
311 exit(0);
312 });
313 }
314
315 /// Override this to perform the specific command. Return a future that
316 /// completes when the command is done or fails if the command fails. If the
317 /// command is synchronous, it may return `null`.
318 Future onRun();
319
320 /// Displays usage information for this command.
321 void printUsage([String description]) {
322 if (description == null) description = this.description;
323
324 var buffer = new StringBuffer();
325 buffer.write('$description\n\nUsage: $usage');
326
327 var commandUsage = commandParser.getUsage();
328 if (!commandUsage.isEmpty) {
329 buffer.write('\n');
330 buffer.write(commandUsage);
331 }
332
333 log.message(buffer.toString());
334 }
335
336 /// Returns the appropriate exit code for [exception], falling back on 1 if no
337 /// appropriate exit code could be found.
338 int _chooseExitCode(exception) {
339 if (exception is HttpException || exception is HttpParserException ||
340 exception is SocketIOException || exception is PubHttpException) {
341 return exit_codes.UNAVAILABLE;
342 } else if (exception is FormatException) {
343 return exit_codes.DATA;
344 } else {
345 return 1;
346 }
347 }
348 }
OLDNEW
« no previous file with comments | « utils/pub/path_source.dart ('k') | utils/pub/pubspec.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698