[flutter_tools] remove all pub caching logic (#66776)

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.
This commit is contained in:
Jonah Williams 2020-10-07 13:11:07 -07:00 committed by GitHub
parent 826b70466a
commit 76cbc462d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 43 additions and 180 deletions

View file

@ -700,8 +700,6 @@ class PubDependencies extends ArtifactSet {
context: PubContext.pubGet, context: PubContext.pubGet,
directory: _fileSystem.path.join(_flutterRoot(), 'packages', 'flutter_tools'), directory: _fileSystem.path.join(_flutterRoot(), 'packages', 'flutter_tools'),
generateSyntheticPackage: false, generateSyntheticPackage: false,
skipPubspecYamlCheck: true,
checkLastModified: false,
); );
} }
} }

View file

@ -117,7 +117,6 @@ class PackagesGetCommand extends FlutterCommand {
directory: directory, directory: directory,
upgrade: upgrade , upgrade: upgrade ,
offline: boolArg('offline'), offline: boolArg('offline'),
checkLastModified: false,
generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage, generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage,
); );
pubGetTimer.stop(); pubGetTimer.stop();

View file

@ -8,11 +8,8 @@ import '../asset.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../build_system/build_system.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../cache.dart'; import '../cache.dart';
import '../dart/generate_synthetic_packages.dart';
import '../dart/pub.dart';
import '../devfs.dart'; import '../devfs.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
@ -169,32 +166,6 @@ class TestCommand extends FlutterCommand {
'directory (or one of its subdirectories).'); 'directory (or one of its subdirectories).');
} }
final FlutterProject flutterProject = FlutterProject.current(); final FlutterProject flutterProject = FlutterProject.current();
if (shouldRunPub) {
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,
);
}
await pub.get(
context: PubContext.getVerifyContext(name),
skipPubspecYamlCheck: true,
generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage,
);
}
final bool buildTestAssets = boolArg('test-assets'); final bool buildTestAssets = boolArg('test-assets');
final List<String> names = stringsArg('name'); final List<String> names = stringsArg('name');
final List<String> plainNames = stringsArg('plain-name'); final List<String> plainNames = stringsArg('plain-name');

View file

@ -330,7 +330,6 @@ class UpdatePackagesCommand extends FlutterCommand {
context: PubContext.updatePackages, context: PubContext.updatePackages,
directory: tempDir.path, directory: tempDir.path,
upgrade: true, upgrade: true,
checkLastModified: false,
offline: offline, offline: offline,
flutterRootOverride: upgrade flutterRootOverride: upgrade
? temporaryFlutterSdk.path ? temporaryFlutterSdk.path
@ -413,7 +412,6 @@ class UpdatePackagesCommand extends FlutterCommand {
await pub.get( await pub.get(
context: PubContext.updatePackages, context: PubContext.updatePackages,
directory: dir.path, directory: dir.path,
checkLastModified: false,
offline: offline, offline: offline,
generateSyntheticPackage: false, generateSyntheticPackage: false,
); );

View file

@ -296,7 +296,6 @@ class UpgradeCommandRunner {
context: PubContext.pubUpgrade, context: PubContext.pubUpgrade,
directory: projectRoot, directory: projectRoot,
upgrade: true, upgrade: true,
checkLastModified: false,
generateSyntheticPackage: false, generateSyntheticPackage: false,
); );
} }

View file

@ -151,7 +151,6 @@ class VersionCommand extends FlutterCommand {
context: PubContext.pubUpgrade, context: PubContext.pubUpgrade,
directory: projectRoot, directory: projectRoot,
upgrade: true, upgrade: true,
checkLastModified: false,
generateSyntheticPackage: false, generateSyntheticPackage: false,
); );
} }

View file

@ -236,8 +236,6 @@ Future<T> runInContext<T>(
botDetector: globals.botDetector, botDetector: globals.botDetector,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
// Avoid a circular dependency by making this access lazy.
toolStampFile: () => globals.cache.getStampFileFor('flutter_tools'),
), ),
ShutdownHooks: () => ShutdownHooks(logger: globals.logger), ShutdownHooks: () => ShutdownHooks(logger: globals.logger),
Stdio: () => Stdio(), Stdio: () => Stdio(),

View file

@ -80,7 +80,6 @@ abstract class Pub {
@required Platform platform, @required Platform platform,
@required BotDetector botDetector, @required BotDetector botDetector,
@required Usage usage, @required Usage usage,
File Function() toolStampFile,
}) = _DefaultPub; }) = _DefaultPub;
/// Runs `pub get`. /// Runs `pub get`.
@ -93,8 +92,6 @@ abstract class Pub {
bool skipIfAbsent = false, bool skipIfAbsent = false,
bool upgrade = false, bool upgrade = false,
bool offline = false, bool offline = false,
bool checkLastModified = true,
bool skipPubspecYamlCheck = false,
bool generateSyntheticPackage = false, bool generateSyntheticPackage = false,
String flutterRootOverride, String flutterRootOverride,
}); });
@ -141,9 +138,7 @@ class _DefaultPub implements Pub {
@required Platform platform, @required Platform platform,
@required BotDetector botDetector, @required BotDetector botDetector,
@required Usage usage, @required Usage usage,
File Function() toolStampFile, }) : _fileSystem = fileSystem,
}) : _toolStampFile = toolStampFile,
_fileSystem = fileSystem,
_logger = logger, _logger = logger,
_platform = platform, _platform = platform,
_botDetector = botDetector, _botDetector = botDetector,
@ -159,7 +154,6 @@ class _DefaultPub implements Pub {
final Platform _platform; final Platform _platform;
final BotDetector _botDetector; final BotDetector _botDetector;
final Usage _usage; final Usage _usage;
final File Function() _toolStampFile;
@override @override
Future<void> get({ Future<void> get({
@ -168,88 +162,52 @@ class _DefaultPub implements Pub {
bool skipIfAbsent = false, bool skipIfAbsent = false,
bool upgrade = false, bool upgrade = false,
bool offline = false, bool offline = false,
bool checkLastModified = true,
bool skipPubspecYamlCheck = false,
bool generateSyntheticPackage = false, bool generateSyntheticPackage = false,
String flutterRootOverride, String flutterRootOverride,
}) async { }) async {
directory ??= _fileSystem.currentDirectory.path; directory ??= _fileSystem.currentDirectory.path;
final File pubSpecYaml = _fileSystem.file(
_fileSystem.path.join(directory, 'pubspec.yaml'));
final File packageConfigFile = _fileSystem.file( final File packageConfigFile = _fileSystem.file(
_fileSystem.path.join(directory, '.dart_tool', 'package_config.json')); _fileSystem.path.join(directory, '.dart_tool', 'package_config.json'));
final Directory generatedDirectory = _fileSystem.directory( final Directory generatedDirectory = _fileSystem.directory(
_fileSystem.path.join(directory, '.dart_tool', 'flutter_gen')); _fileSystem.path.join(directory, '.dart_tool', 'flutter_gen'));
if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) { final String command = upgrade ? 'upgrade' : 'get';
if (!skipIfAbsent) { final Status status = _logger.startProgress(
throwToolExit('$directory: no pubspec.yaml found'); 'Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...',
} timeout: const TimeoutConfiguration().slowOperation,
return; );
} final bool verbose = _logger.isVerbose;
final List<String> args = <String>[
final DateTime originalPubspecYamlModificationTime = pubSpecYaml.lastModifiedSync(); if (verbose)
'--verbose'
if (!checkLastModified || _shouldRunPubGet( else
pubSpecYaml: pubSpecYaml, '--verbosity=warning',
packageConfigFile: packageConfigFile, ...<String>[
)) { command,
final String command = upgrade ? 'upgrade' : 'get'; '--no-precompile',
final Status status = _logger.startProgress( ],
'Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...', if (offline)
timeout: const TimeoutConfiguration().slowOperation, '--offline',
];
try {
await batch(
args,
context: context,
directory: directory,
failureMessage: 'pub $command failed',
retry: true,
flutterRootOverride: flutterRootOverride,
); );
final bool verbose = _logger.isVerbose; status.stop();
final List<String> args = <String>[ // The exception is rethrown, so don't catch only Exceptions.
if (verbose) } catch (exception) { // ignore: avoid_catches_without_on_clauses
'--verbose' status.cancel();
else rethrow;
'--verbosity=warning',
...<String>[
command,
'--no-precompile',
],
if (offline)
'--offline',
];
try {
await batch(
args,
context: context,
directory: directory,
failureMessage: 'pub $command failed',
retry: true,
flutterRootOverride: flutterRootOverride,
);
status.stop();
// The exception is rethrown, so don't catch only Exceptions.
} catch (exception) { // ignore: avoid_catches_without_on_clauses
status.cancel();
rethrow;
}
} }
if (!packageConfigFile.existsSync()) { if (!packageConfigFile.existsSync()) {
throwToolExit('$directory: pub did not create .dart_tools/package_config.json file.'); throwToolExit('$directory: pub did not create .dart_tools/package_config.json file.');
} }
if (pubSpecYaml.lastModifiedSync() != originalPubspecYamlModificationTime) {
throwToolExit(
'$directory: unexpected concurrent modification of '
'pubspec.yaml while running pub.');
}
// We don't check if dotPackages was actually modified, because as far as we can tell sometimes
// pub will decide it does not need to actually modify it.
final DateTime now = DateTime.now();
if (now.isBefore(originalPubspecYamlModificationTime)) {
_logger.printError(
'Warning: File "${_fileSystem.path.absolute(pubSpecYaml.path)}" was created in the future. '
'Optimizations that rely on comparing time stamps will be unreliable. Check your '
'system clock for accuracy.\n'
'The timestamp was: $originalPubspecYamlModificationTime\n'
'The time now is: $now'
);
}
await _updatePackageConfig( await _updatePackageConfig(
packageConfigFile, packageConfigFile,
generatedDirectory, generatedDirectory,
@ -392,23 +350,6 @@ class _DefaultPub implements Pub {
return <String>[sdkPath, ...arguments]; return <String>[sdkPath, ...arguments];
} }
bool _shouldRunPubGet({ @required File pubSpecYaml, @required File packageConfigFile }) {
if (!packageConfigFile.existsSync()) {
return true;
}
final DateTime dotPackagesLastModified = packageConfigFile.lastModifiedSync();
if (pubSpecYaml.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true;
}
final File toolStampFile = _toolStampFile != null ? _toolStampFile() : null;
if (toolStampFile != null &&
toolStampFile.existsSync() &&
toolStampFile.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true;
}
return false;
}
// Returns the environment value that should be used when running pub. // Returns the environment value that should be used when running pub.
// //
// Includes any existing environment variable, if one exists. // Includes any existing environment variable, if one exists.

View file

@ -950,9 +950,9 @@ abstract class FlutterCommand extends Command<void> {
// First always update universal artifacts, as some of these (e.g. // First always update universal artifacts, as some of these (e.g.
// ios-deploy on macOS) are required to determine `requiredArtifacts`. // ios-deploy on macOS) are required to determine `requiredArtifacts`.
await globals.cache.updateAll(<DevelopmentArtifact>{DevelopmentArtifact.universal}); await globals.cache.updateAll(<DevelopmentArtifact>{DevelopmentArtifact.universal});
await globals.cache.updateAll(await requiredArtifacts); await globals.cache.updateAll(await requiredArtifacts);
} }
Cache.releaseLock();
await validateCommand(); await validateCommand();
@ -979,11 +979,7 @@ abstract class FlutterCommand extends Command<void> {
context: PubContext.getVerifyContext(name), context: PubContext.getVerifyContext(name),
generateSyntheticPackage: project.manifest.generateSyntheticPackage, generateSyntheticPackage: project.manifest.generateSyntheticPackage,
); );
// All done updating dependencies. Release the cache lock.
Cache.releaseLock();
await project.ensureReadyForPlatformSpecificTooling(checkProjects: true); await project.ensureReadyForPlatformSpecificTooling(checkProjects: true);
} else {
Cache.releaseLock();
} }
setupApplicationPackages(); setupApplicationPackages();

View file

@ -743,9 +743,6 @@ void main() {
verify(pub.get( verify(pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: 'packages/flutter_tools', directory: 'packages/flutter_tools',
generateSyntheticPackage: false,
skipPubspecYamlCheck: true,
checkLastModified: false,
)).called(1); )).called(1);
}); });
} }

View file

@ -49,7 +49,7 @@ void main() {
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
expect(processMock.lastPubEnvironment, isNull); expect(processMock.lastPubEnvironment, isNull);
expect(logger.statusText, ''); expect(logger.statusText, '');
pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) { pub.get(context: PubContext.flutterTests).then((void value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
@ -114,7 +114,7 @@ void main() {
processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'), processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
); );
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests);
throw AssertionError('pubGet did not fail'); throw AssertionError('pubGet did not fail');
} on ToolExit catch (error) { } on ToolExit catch (error) {
expect(error.message, 'pub get failed (66; err3)'); expect(error.message, 'pub get failed (66; err3)');
@ -149,7 +149,7 @@ void main() {
MockDirectory.findCache = true; MockDirectory.findCache = true;
expect(processMock.lastPubEnvironment, isNull); expect(processMock.lastPubEnvironment, isNull);
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) { pub.get(context: PubContext.flutterTests).then((void value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
@ -182,7 +182,7 @@ void main() {
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
String error; String error;
pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) { pub.get(context: PubContext.flutterTests).then((void value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
@ -217,7 +217,6 @@ void main() {
await pub.get( await pub.get(
context: PubContext.flutterTests, context: PubContext.flutterTests,
generateSyntheticPackage: true, generateSyntheticPackage: true,
checkLastModified: false,
); );
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
@ -255,7 +254,6 @@ void main() {
await pub.get( await pub.get(
context: PubContext.flutterTests, context: PubContext.flutterTests,
generateSyntheticPackage: true, generateSyntheticPackage: true,
checkLastModified: false,
); );
expect( expect(
@ -285,7 +283,7 @@ void main() {
), ),
); );
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
@ -314,7 +312,7 @@ void main() {
fileSystem.file('pubspec.yaml').writeAsStringSync('name: foo'); fileSystem.file('pubspec.yaml').writeAsStringSync('name: foo');
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
@ -386,7 +384,7 @@ void main() {
fileSystem.file('pubspec.yaml') fileSystem.file('pubspec.yaml')
..createSync() ..createSync()
..setLastModifiedSync(DateTime(2001)); ..setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub sets date of .packages to 2002 await pub.get(context: PubContext.flutterTests); // pub sets date of .packages to 2002
expect(logger.statusText, 'Running "flutter pub get" in /...\n'); expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty); expect(logger.errorText, isEmpty);
@ -398,44 +396,12 @@ void main() {
.setLastModifiedSync(DateTime(2000)); .setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml') fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001)); .setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing await pub.get(context: PubContext.flutterTests); // pub does nothing
expect(logger.statusText, 'Running "flutter pub get" in /...\n'); expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty); expect(logger.errorText, isEmpty);
expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it
logger.clear(); logger.clear();
// bad scenario 2: pub changes pubspec.yaml instead
fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001));
try {
await pub.get(context: PubContext.flutterTests, checkLastModified: true);
expect(true, isFalse, reason: 'pub.get did not throw');
} on ToolExit catch (error) {
expect(error.message, '/: unexpected concurrent modification of pubspec.yaml while running pub.');
}
expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty);
expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2002)); // because fake pub above touched it
// bad scenario 3: pubspec.yaml was created in the future
fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(9999));
assert(DateTime(9999).isAfter(DateTime.now()));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing
expect(logger.statusText, contains('Running "flutter pub get" in /...\n'));
expect(logger.errorText, startsWith(
'Warning: File "/pubspec.yaml" was created in the future. Optimizations that rely on '
'comparing time stamps will be unreliable. Check your system clock for accuracy.\n'
'The timestamp was:'
));
logger.clear();
}); });
} }

View file

@ -24,7 +24,8 @@ final ProcessUtils processUtils = ProcessUtils(processManager: processManager, l
outputPreferences: OutputPreferences.test(wrapText: true), outputPreferences: OutputPreferences.test(wrapText: true),
timeoutConfiguration: const TimeoutConfiguration(), timeoutConfiguration: const TimeoutConfiguration(),
)); ));
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); 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');
/// A test for flutter upgrade & downgrade that checks out a parallel flutter repo. /// A test for flutter upgrade & downgrade that checks out a parallel flutter repo.
void main() { void main() {