| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'package:args/args.dart'; | |
| import 'package:args/command_runner.dart'; | |
| import 'command.dart' show PubTopLevel, lineLength; | |
| import 'command/add.dart'; | |
| import 'command/bump.dart'; | |
| import 'command/cache.dart'; | |
| import 'command/check_resolution_up_to_date.dart'; | |
| import 'command/deps.dart'; | |
| import 'command/downgrade.dart'; | |
| import 'command/get.dart'; | |
| import 'command/global.dart'; | |
| import 'command/lish.dart'; | |
| import 'command/login.dart'; | |
| import 'command/logout.dart'; | |
| import 'command/outdated.dart'; | |
| import 'command/remove.dart'; | |
| import 'command/run.dart'; | |
| import 'command/token.dart'; | |
| import 'command/unpack.dart'; | |
| import 'command/upgrade.dart'; | |
| import 'command/uploader.dart'; | |
| import 'command/version.dart'; | |
| import 'command/workspace.dart'; | |
| import 'exit_codes.dart' as exit_codes; | |
| import 'git.dart' as git; | |
| import 'io.dart'; | |
| import 'log.dart' as log; | |
| import 'log.dart'; | |
| import 'path.dart'; | |
| import 'platform_info.dart'; | |
| import 'sdk.dart'; | |
| import 'utils.dart'; | |
| /// The name of the program that is invoking pub | |
| /// 'flutter' if we are running inside `flutter pub` 'dart' otherwise. | |
| String topLevelProgram = _isRunningInsideFlutter ? 'flutter' : 'dart'; | |
| bool _isRunningInsideFlutter = (platform.environment['PUB_ENVIRONMENT'] ?? '') | |
| .contains('flutter_cli'); | |
| class PubCommandRunner extends CommandRunner<int> implements PubTopLevel { | |
| @override | |
| String get directory => argResults.optionWithDefault('directory'); | |
| @override | |
| bool get captureStackChains { | |
| return argResults.flag('trace') || | |
| argResults.flag('verbose') || | |
| argResults.option('verbosity') == 'all'; | |
| } | |
| @override | |
| Verbosity get verbosity { | |
| switch (argResults['verbosity']) { | |
| case 'error': | |
| return log.Verbosity.error; | |
| case 'warning': | |
| return log.Verbosity.warning; | |
| case 'normal': | |
| return log.Verbosity.normal; | |
| case 'io': | |
| return log.Verbosity.io; | |
| case 'solver': | |
| return log.Verbosity.solver; | |
| case 'all': | |
| return log.Verbosity.all; | |
| default: | |
| // No specific verbosity given, so check for the shortcut. | |
| if (argResults.flag('verbose')) return log.Verbosity.all; | |
| if (runningFromTest) return log.Verbosity.testing; | |
| return log.Verbosity.normal; | |
| } | |
| } | |
| @override | |
| bool get trace => argResults.flag('trace'); | |
| ArgResults? _argResults; | |
| /// The top-level options parsed by the command runner. | |
| @override | |
| ArgResults get argResults { | |
| final a = _argResults; | |
| if (a == null) { | |
| throw StateError( | |
| 'argResults cannot be used before Command.run is called.', | |
| ); | |
| } | |
| return a; | |
| } | |
| @override | |
| String get usageFooter => | |
| 'See https://dart.dev/tools/pub/cmd for detailed documentation.'; | |
| PubCommandRunner() | |
| : super( | |
| 'pub', | |
| 'Pub is a package manager for Dart.', | |
| usageLineLength: lineLength, | |
| ) { | |
| 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: ['error', 'warning', 'normal', 'io', 'solver', 'all'], | |
| allowedHelp: { | |
| 'error': 'Show only errors.', | |
| 'warning': 'Show only errors and warnings.', | |
| '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".', | |
| ); | |
| PubTopLevel.addColorFlag(argParser); | |
| argParser.addOption( | |
| 'directory', | |
| abbr: 'C', | |
| help: 'Run the subcommand in the directory<dir>.', | |
| defaultsTo: '.', | |
| valueHelp: 'dir', | |
| ); | |
| // When adding new commands be sure to also add them to | |
| // `pub_embeddable_command.dart`. | |
| addCommand(AddCommand()); | |
| addCommand(BumpCommand()); | |
| addCommand(CacheCommand()); | |
| addCommand(DepsCommand()); | |
| addCommand(DowngradeCommand()); | |
| addCommand(GlobalCommand()); | |
| addCommand(GetCommand()); | |
| addCommand(LishCommand()); | |
| addCommand(OutdatedCommand()); | |
| addCommand(RemoveCommand()); | |
| addCommand(RunCommand()); | |
| addCommand(CheckResolutionUpToDateCommand()); | |
| addCommand(UpgradeCommand()); | |
| addCommand(UnpackCommand()); | |
| addCommand(UploaderCommand()); | |
| addCommand(LoginCommand()); | |
| addCommand(LogoutCommand()); | |
| addCommand(VersionCommand()); | |
| addCommand(WorkspaceCommand()); | |
| addCommand(TokenCommand()); | |
| } | |
| @override | |
| Future<int> run(Iterable<String> args) async { | |
| try { | |
| final argResults = parse(args); | |
| _argResults = argResults; | |
| return await runCommand(argResults) ?? exit_codes.SUCCESS; | |
| } on UsageException catch (error) { | |
| log.exception(error); | |
| return exit_codes.USAGE; | |
| } | |
| } | |
| @override | |
| Future<int?> runCommand(ArgResults topLevelResults) async { | |
| _checkDepsSynced(); | |
| if (topLevelResults.flag('version')) { | |
| log.message('Pub ${sdk.version}'); | |
| return 0; | |
| } | |
| return await super.runCommand(topLevelResults); | |
| } | |
| @override | |
| void printUsage() { | |
| log.message(usage); | |
| } | |
| /// Print a warning if we're running from the Dart SDK repo and pub isn't | |
| /// up-to-date. | |
| /// | |
| /// This is otherwise hard to tell, and can produce confusing behavior issues. | |
| void _checkDepsSynced() { | |
| if (!runningFromDartRepo) return; | |
| if (!git.isInstalled) return; | |
| final deps = readTextFile(p.join(dartRepoRoot, 'DEPS')); | |
| final pubRevRegExp = RegExp(r'^ +"pub_rev": +"@([^"]+)"', multiLine: true); | |
| final match = pubRevRegExp.firstMatch(deps); | |
| if (match == null) return; | |
| final depsRev = match[1]; | |
| String actualRev; | |
| final pubRoot = p.dirname(p.dirname(p.fromUri(platform.script))); | |
| try { | |
| actualRev = | |
| git.runSync(['rev-parse', 'HEAD'], workingDir: pubRoot).trim(); | |
| } on git.GitException catch (_) { | |
| // When building for Debian, pub isn't checked out via git. | |
| return; | |
| } | |
| if (depsRev == actualRev) return; | |
| log.warning( | |
| "${log.yellow('Warning:')} the revision of pub in DEPS is " | |
| '${log.bold(depsRev.toString())},\n' | |
| 'but ${log.bold(actualRev)} is checked out in ' | |
| '${p.relative(pubRoot)}.\n\n', | |
| ); | |
| } | |
| } |