Unverified Commit a0be9802 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] ensure pub get can run from partially valid state (#74249)

parent 7a413e71
......@@ -76,6 +76,8 @@ class PackagesGetCommand extends FlutterCommand {
return '${runner.executableName} pub $name [<target directory>]';
}
/// The pub packages usage values are incorrect since these are calculated/sent
/// before pub get completes. This needs to be performed after dependency resolution.
@override
Future<Map<CustomDimensions, String>> get usageValues async {
final Map<CustomDimensions, String> usageValues = <CustomDimensions, String>{};
......@@ -85,9 +87,14 @@ class PackagesGetCommand extends FlutterCommand {
return usageValues;
}
final FlutterProject rootProject = FlutterProject.fromPath(target);
final bool hasPlugins = rootProject.flutterPluginsDependenciesFile.existsSync();
// Do not send plugin analytics if pub has not run before.
final bool hasPlugins = rootProject.flutterPluginsDependenciesFile.existsSync()
&& rootProject.packagesFile.existsSync()
&& rootProject.packageConfigFile.existsSync();
if (hasPlugins) {
final List<Plugin> plugins = await findPlugins(rootProject);
// Do not fail pub get if package config files are invalid before pub has
// had a chance to run.
final List<Plugin> plugins = await findPlugins(rootProject, throwOnError: false);
usageValues[CustomDimensions.commandPackagesNumberPlugins] = plugins.length.toString();
} else {
usageValues[CustomDimensions.commandPackagesNumberPlugins] = '0';
......
......@@ -345,7 +345,7 @@ Plugin _pluginFromPackage(String name, Uri packageRoot) {
);
}
Future<List<Plugin>> findPlugins(FlutterProject project) async {
Future<List<Plugin>> findPlugins(FlutterProject project, { bool throwOnError = true}) async {
final List<Plugin> plugins = <Plugin>[];
final String packagesFile = globals.fs.path.join(
project.directory.path,
......@@ -354,6 +354,7 @@ Future<List<Plugin>> findPlugins(FlutterProject project) async {
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
globals.fs.file(packagesFile),
logger: globals.logger,
throwOnError: throwOnError,
);
for (final Package package in packageConfig.packages) {
final Uri packageRoot = package.packageUriRoot.resolve('..');
......
......@@ -162,6 +162,12 @@ class FlutterProject {
/// The `.packages` file of this project.
File get packagesFile => directory.childFile('.packages');
/// The `package_config.json` file of the project.
///
/// This is the replacement for .packages which contains language
/// version information.
File get packageConfigFile => directory.childDirectory('.dart_tool').childFile('package_config.json');
/// The `.metadata` file of this project.
File get metadataFile => directory.childFile('.metadata');
......
// 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 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/packages.dart';
import 'package:flutter_tools/src/dart/pub.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:meta/meta.dart';
import 'package:test/fake.dart';
import '../../src/common.dart';
import '../../src/context.dart';
void main() {
FileSystem fileSystem;
FakePub pub;
setUp(() {
Cache.disableLocking();
fileSystem = MemoryFileSystem.test();
pub = FakePub(fileSystem);
});
tearDown(() {
Cache.enableLocking();
});
testUsingContext('pub get usage values are resilient to missing package config files before running "pub get"', () async {
fileSystem.currentDirectory.childFile('pubspec.yaml').createSync();
fileSystem.currentDirectory.childFile('.flutter-plugins').createSync();
fileSystem.currentDirectory.childFile('.flutter-plugins-dependencies').createSync();
final PackagesGetCommand command = PackagesGetCommand('get', false);
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
await commandRunner.run(<String>['get']);
expect(await command.usageValues, <CustomDimensions, Object>{
CustomDimensions.commandPackagesNumberPlugins: '0',
CustomDimensions.commandPackagesProjectModule: 'false',
CustomDimensions.commandPackagesAndroidEmbeddingVersion: 'v1'
});
}, overrides: <Type, Generator>{
Pub: () => pub,
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => fileSystem,
});
testUsingContext('pub get usage values are resilient to poorly formatted package config before "pub get"', () async {
fileSystem.currentDirectory.childFile('pubspec.yaml').createSync();
fileSystem.currentDirectory.childFile('.flutter-plugins').createSync();
fileSystem.currentDirectory.childFile('.flutter-plugins-dependencies').createSync();
fileSystem.currentDirectory.childFile('.packages').writeAsBytesSync(<int>[0]);
fileSystem.currentDirectory.childFile('.dart_tool/package_config.json')
..createSync(recursive: true)
..writeAsBytesSync(<int>[0]);
final PackagesGetCommand command = PackagesGetCommand('get', false);
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
await commandRunner.run(<String>['get']);
expect(await command.usageValues, <CustomDimensions, Object>{
CustomDimensions.commandPackagesNumberPlugins: '0',
CustomDimensions.commandPackagesProjectModule: 'false',
CustomDimensions.commandPackagesAndroidEmbeddingVersion: 'v1'
});
}, overrides: <Type, Generator>{
Pub: () => pub,
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => fileSystem,
});
}
class FakePub extends Fake implements Pub {
FakePub(this.fileSystem);
final FileSystem fileSystem;
@override
Future<void> get({
@required PubContext context,
String directory,
bool skipIfAbsent = false,
bool upgrade = false,
bool offline = false,
bool generateSyntheticPackage = false,
String flutterRootOverride,
bool checkUpToDate = false,
}) async {
fileSystem.currentDirectory
.childDirectory('.dart_tool')
.childFile('package_config.json')
..createSync(recursive: true)
..writeAsStringSync('{"configVersion":2,"packages":[]}');
}
}
......@@ -8,10 +8,10 @@ import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'test_utils.dart';
/// Verifies that `dart migrate` will run successfuly on the default `flutter create`
/// Verifies that `dart migrate` will run successfully on the default `flutter create`
/// template.
void main() {
testWithoutContext('dart migrate succeedes on flutter create template', () async {
testWithoutContext('dart migrate succeeds on flutter create template', () async {
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter');
final String dartBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'dart.bat' : 'dart');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment