mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

There have been some more additional reports of a missing 'package:characters' import after upgrading flutter, as well as problems with detecting the correct language version. This has me concerned that our pub caching logic is incorrect. Instead of the tool attempting to guess when pub should be run, always delegate to pub.
288 lines
9.3 KiB
Dart
288 lines
9.3 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import '../base/common.dart';
|
|
import '../base/os.dart';
|
|
import '../build_info.dart';
|
|
import '../build_system/build_system.dart';
|
|
import '../cache.dart';
|
|
import '../dart/generate_synthetic_packages.dart';
|
|
import '../dart/pub.dart';
|
|
import '../globals.dart' as globals;
|
|
import '../project.dart';
|
|
import '../reporting/reporting.dart';
|
|
import '../runner/flutter_command.dart';
|
|
|
|
class PackagesCommand extends FlutterCommand {
|
|
PackagesCommand() {
|
|
addSubcommand(PackagesGetCommand('get', false));
|
|
addSubcommand(PackagesGetCommand('upgrade', true));
|
|
addSubcommand(PackagesTestCommand());
|
|
addSubcommand(PackagesPublishCommand());
|
|
addSubcommand(PackagesForwardCommand('downgrade', 'Downgrade packages in a Flutter project', requiresPubspec: true));
|
|
addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies', requiresPubspec: true));
|
|
addSubcommand(PackagesForwardCommand('run', 'Run an executable from a package', requiresPubspec: true));
|
|
addSubcommand(PackagesForwardCommand('cache', 'Work with the Pub system cache'));
|
|
addSubcommand(PackagesForwardCommand('version', 'Print Pub version'));
|
|
addSubcommand(PackagesForwardCommand('uploader', 'Manage uploaders for a package on pub.dev'));
|
|
addSubcommand(PackagesForwardCommand('global', 'Work with Pub global packages'));
|
|
addSubcommand(PackagesForwardCommand('outdated', 'Analyze dependencies to find which ones can be upgraded', requiresPubspec: true));
|
|
addSubcommand(PackagesPassthroughCommand());
|
|
}
|
|
|
|
@override
|
|
final String name = 'pub';
|
|
|
|
@override
|
|
List<String> get aliases => const <String>['packages'];
|
|
|
|
@override
|
|
final String description = 'Commands for managing Flutter packages.';
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async => null;
|
|
}
|
|
|
|
class PackagesGetCommand extends FlutterCommand {
|
|
PackagesGetCommand(this.name, this.upgrade) {
|
|
requiresPubspecYaml();
|
|
argParser.addFlag('offline',
|
|
negatable: false,
|
|
help: 'Use cached packages instead of accessing the network.',
|
|
);
|
|
}
|
|
|
|
@override
|
|
final String name;
|
|
|
|
final bool upgrade;
|
|
|
|
@override
|
|
String get description {
|
|
return '${ upgrade ? "Upgrade" : "Get" } packages in a Flutter project.';
|
|
}
|
|
|
|
@override
|
|
String get invocation {
|
|
return '${runner.executableName} pub $name [<target directory>]';
|
|
}
|
|
|
|
@override
|
|
Future<Map<CustomDimensions, String>> get usageValues async {
|
|
final Map<CustomDimensions, String> usageValues = <CustomDimensions, String>{};
|
|
final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
|
|
final String target = findProjectRoot(workingDirectory);
|
|
if (target == null) {
|
|
return usageValues;
|
|
}
|
|
final FlutterProject rootProject = FlutterProject.fromPath(target);
|
|
final bool hasPlugins = rootProject.flutterPluginsFile.existsSync();
|
|
if (hasPlugins) {
|
|
final int numberOfPlugins = (rootProject.flutterPluginsFile.readAsLinesSync()).length;
|
|
usageValues[CustomDimensions.commandPackagesNumberPlugins] = '$numberOfPlugins';
|
|
} else {
|
|
usageValues[CustomDimensions.commandPackagesNumberPlugins] = '0';
|
|
}
|
|
usageValues[CustomDimensions.commandPackagesProjectModule] = '${rootProject.isModule}';
|
|
usageValues[CustomDimensions.commandPackagesAndroidEmbeddingVersion] =
|
|
rootProject.android.getEmbeddingVersion().toString().split('.').last;
|
|
return usageValues;
|
|
}
|
|
|
|
Future<void> _runPubGet(String directory, FlutterProject flutterProject) async {
|
|
if (flutterProject.manifest.generateSyntheticPackage) {
|
|
final Environment environment = Environment(
|
|
artifacts: globals.artifacts,
|
|
logger: globals.logger,
|
|
cacheDir: globals.cache.getRoot(),
|
|
engineVersion: globals.flutterVersion.engineRevision,
|
|
fileSystem: globals.fs,
|
|
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
|
|
outputDir: globals.fs.directory(getBuildDirectory()),
|
|
processManager: globals.processManager,
|
|
projectDir: flutterProject.directory,
|
|
);
|
|
|
|
await generateLocalizationsSyntheticPackage(
|
|
environment: environment,
|
|
buildSystem: globals.buildSystem,
|
|
);
|
|
}
|
|
|
|
final Stopwatch pubGetTimer = Stopwatch()..start();
|
|
try {
|
|
await pub.get(
|
|
context: PubContext.pubGet,
|
|
directory: directory,
|
|
upgrade: upgrade ,
|
|
offline: boolArg('offline'),
|
|
generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage,
|
|
);
|
|
pubGetTimer.stop();
|
|
globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success');
|
|
// Not limiting to catching Exception because the exception is rethrown.
|
|
} catch (_) { // ignore: avoid_catches_without_on_clauses
|
|
pubGetTimer.stop();
|
|
globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
if (argResults.rest.length > 1) {
|
|
throwToolExit('Too many arguments.\n$usage');
|
|
}
|
|
|
|
final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
|
|
final String target = findProjectRoot(workingDirectory);
|
|
if (target == null) {
|
|
throwToolExit(
|
|
'Expected to find project root in '
|
|
'${ workingDirectory ?? "current working directory" }.'
|
|
);
|
|
}
|
|
final FlutterProject rootProject = FlutterProject.fromPath(target);
|
|
|
|
await _runPubGet(target, rootProject);
|
|
await rootProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
|
|
|
|
// Get/upgrade packages in example app as well
|
|
if (rootProject.hasExampleApp) {
|
|
final FlutterProject exampleProject = rootProject.example;
|
|
await _runPubGet(exampleProject.directory.path, exampleProject);
|
|
await exampleProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
|
|
}
|
|
|
|
return FlutterCommandResult.success();
|
|
}
|
|
}
|
|
|
|
class PackagesTestCommand extends FlutterCommand {
|
|
PackagesTestCommand() {
|
|
requiresPubspecYaml();
|
|
}
|
|
|
|
@override
|
|
String get name => 'test';
|
|
|
|
@override
|
|
String get description {
|
|
return 'Run the "test" package.\n'
|
|
'This is similar to "flutter test", but instead of hosting the tests in the '
|
|
'flutter environment it hosts the tests in a pure Dart environment. The main '
|
|
'differences are that the "dart:ui" library is not available and that tests '
|
|
'run faster. This is helpful for testing libraries that do not depend on any '
|
|
'packages from the Flutter SDK. It is equivalent to "pub run test".';
|
|
}
|
|
|
|
@override
|
|
String get invocation {
|
|
return '${runner.executableName} pub test [<tests...>]';
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
await pub.batch(<String>['run', 'test', ...argResults.rest], context: PubContext.runTest, retry: false);
|
|
return FlutterCommandResult.success();
|
|
}
|
|
}
|
|
|
|
class PackagesPublishCommand extends FlutterCommand {
|
|
PackagesPublishCommand() {
|
|
requiresPubspecYaml();
|
|
argParser.addFlag('dry-run',
|
|
abbr: 'n',
|
|
negatable: false,
|
|
help: 'Validate but do not publish the package.',
|
|
);
|
|
argParser.addFlag('force',
|
|
abbr: 'f',
|
|
negatable: false,
|
|
help: 'Publish without confirmation if there are no errors.',
|
|
);
|
|
}
|
|
|
|
@override
|
|
String get name => 'publish';
|
|
|
|
@override
|
|
String get description {
|
|
return 'Publish the current package to pub.dev';
|
|
}
|
|
|
|
@override
|
|
String get invocation {
|
|
return '${runner.executableName} pub publish [--dry-run]';
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
final List<String> args = <String>[
|
|
...argResults.rest,
|
|
if (boolArg('dry-run')) '--dry-run',
|
|
if (boolArg('force')) '--force',
|
|
];
|
|
await pub.interactively(<String>['publish', ...args], stdio: globals.stdio);
|
|
return FlutterCommandResult.success();
|
|
}
|
|
}
|
|
|
|
class PackagesForwardCommand extends FlutterCommand {
|
|
PackagesForwardCommand(this._commandName, this._description, {bool requiresPubspec = false}) {
|
|
if (requiresPubspec) {
|
|
requiresPubspecYaml();
|
|
}
|
|
}
|
|
final String _commandName;
|
|
final String _description;
|
|
|
|
@override
|
|
String get name => _commandName;
|
|
|
|
@override
|
|
String get description {
|
|
return '$_description.\n'
|
|
'This runs the "pub" tool in a Flutter context.';
|
|
}
|
|
|
|
@override
|
|
String get invocation {
|
|
return '${runner.executableName} pub $_commandName [<arguments...>]';
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
await pub.interactively(<String>[_commandName, ...argResults.rest], stdio: globals.stdio);
|
|
return FlutterCommandResult.success();
|
|
}
|
|
|
|
}
|
|
|
|
class PackagesPassthroughCommand extends FlutterCommand {
|
|
PackagesPassthroughCommand() {
|
|
requiresPubspecYaml();
|
|
}
|
|
|
|
@override
|
|
String get name => 'pub';
|
|
|
|
@override
|
|
String get description {
|
|
return 'Pass the remaining arguments to Dart\'s "pub" tool.\n'
|
|
'This runs the "pub" tool in a Flutter context.';
|
|
}
|
|
|
|
@override
|
|
String get invocation {
|
|
return '${runner.executableName} packages pub [<arguments...>]';
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
await pub.interactively(argResults.rest, stdio: globals.stdio);
|
|
return FlutterCommandResult.success();
|
|
}
|
|
}
|