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

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

This reverts commit 76cbc462.
parent 5e4c86d1
...@@ -700,6 +700,8 @@ class PubDependencies extends ArtifactSet { ...@@ -700,6 +700,8 @@ 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,
); );
} }
} }
......
...@@ -117,6 +117,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -117,6 +117,7 @@ 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();
......
...@@ -8,8 +8,11 @@ import '../asset.dart'; ...@@ -8,8 +8,11 @@ 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';
...@@ -166,6 +169,32 @@ class TestCommand extends FlutterCommand { ...@@ -166,6 +169,32 @@ 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');
......
...@@ -330,6 +330,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -330,6 +330,7 @@ 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
...@@ -412,6 +413,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -412,6 +413,7 @@ 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,
); );
......
...@@ -296,6 +296,7 @@ class UpgradeCommandRunner { ...@@ -296,6 +296,7 @@ class UpgradeCommandRunner {
context: PubContext.pubUpgrade, context: PubContext.pubUpgrade,
directory: projectRoot, directory: projectRoot,
upgrade: true, upgrade: true,
checkLastModified: false,
generateSyntheticPackage: false, generateSyntheticPackage: false,
); );
} }
......
...@@ -151,6 +151,7 @@ class VersionCommand extends FlutterCommand { ...@@ -151,6 +151,7 @@ class VersionCommand extends FlutterCommand {
context: PubContext.pubUpgrade, context: PubContext.pubUpgrade,
directory: projectRoot, directory: projectRoot,
upgrade: true, upgrade: true,
checkLastModified: false,
generateSyntheticPackage: false, generateSyntheticPackage: false,
); );
} }
......
...@@ -236,6 +236,8 @@ Future<T> runInContext<T>( ...@@ -236,6 +236,8 @@ 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(),
......
...@@ -80,6 +80,7 @@ abstract class Pub { ...@@ -80,6 +80,7 @@ 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`.
...@@ -92,6 +93,8 @@ abstract class Pub { ...@@ -92,6 +93,8 @@ 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,
}); });
...@@ -138,7 +141,9 @@ class _DefaultPub implements Pub { ...@@ -138,7 +141,9 @@ class _DefaultPub implements Pub {
@required Platform platform, @required Platform platform,
@required BotDetector botDetector, @required BotDetector botDetector,
@required Usage usage, @required Usage usage,
}) : _fileSystem = fileSystem, File Function() toolStampFile,
}) : _toolStampFile = toolStampFile,
_fileSystem = fileSystem,
_logger = logger, _logger = logger,
_platform = platform, _platform = platform,
_botDetector = botDetector, _botDetector = botDetector,
...@@ -154,6 +159,7 @@ class _DefaultPub implements Pub { ...@@ -154,6 +159,7 @@ 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({
...@@ -162,52 +168,88 @@ class _DefaultPub implements Pub { ...@@ -162,52 +168,88 @@ 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'));
final String command = upgrade ? 'upgrade' : 'get'; if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) {
final Status status = _logger.startProgress( if (!skipIfAbsent) {
'Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...', throwToolExit('$directory: no pubspec.yaml found');
timeout: const TimeoutConfiguration().slowOperation, }
); return;
final bool verbose = _logger.isVerbose; }
final List<String> args = <String>[
if (verbose) final DateTime originalPubspecYamlModificationTime = pubSpecYaml.lastModifiedSync();
'--verbose'
else if (!checkLastModified || _shouldRunPubGet(
'--verbosity=warning', pubSpecYaml: pubSpecYaml,
...<String>[ packageConfigFile: packageConfigFile,
command, )) {
'--no-precompile', final String command = upgrade ? 'upgrade' : 'get';
], final Status status = _logger.startProgress(
if (offline) 'Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...',
'--offline', timeout: const TimeoutConfiguration().slowOperation,
];
try {
await batch(
args,
context: context,
directory: directory,
failureMessage: 'pub $command failed',
retry: true,
flutterRootOverride: flutterRootOverride,
); );
status.stop(); final bool verbose = _logger.isVerbose;
// The exception is rethrown, so don't catch only Exceptions. final List<String> args = <String>[
} catch (exception) { // ignore: avoid_catches_without_on_clauses if (verbose)
status.cancel(); '--verbose'
rethrow; else
'--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,
...@@ -350,6 +392,23 @@ class _DefaultPub implements Pub { ...@@ -350,6 +392,23 @@ 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.
......
...@@ -950,9 +950,9 @@ abstract class FlutterCommand extends Command<void> { ...@@ -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,7 +979,11 @@ abstract class FlutterCommand extends Command<void> { ...@@ -979,7 +979,11 @@ 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();
......
...@@ -743,6 +743,9 @@ void main() { ...@@ -743,6 +743,9 @@ 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);
}); });
} }
......
...@@ -49,7 +49,7 @@ void main() { ...@@ -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).then((void value) { pub.get(context: PubContext.flutterTests, checkLastModified: false).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() { ...@@ -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); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
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() { ...@@ -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).then((void value) { pub.get(context: PubContext.flutterTests, checkLastModified: false).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() { ...@@ -182,7 +182,7 @@ void main() {
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
String error; String error;
pub.get(context: PubContext.flutterTests).then((void value) { pub.get(context: PubContext.flutterTests, checkLastModified: false).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,6 +217,7 @@ void main() { ...@@ -217,6 +217,7 @@ 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);
...@@ -254,6 +255,7 @@ void main() { ...@@ -254,6 +255,7 @@ void main() {
await pub.get( await pub.get(
context: PubContext.flutterTests, context: PubContext.flutterTests,
generateSyntheticPackage: true, generateSyntheticPackage: true,
checkLastModified: false,
); );
expect( expect(
...@@ -283,7 +285,7 @@ void main() { ...@@ -283,7 +285,7 @@ void main() {
), ),
); );
try { try {
await pub.get(context: PubContext.flutterTests); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
...@@ -312,7 +314,7 @@ void main() { ...@@ -312,7 +314,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); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
...@@ -384,7 +386,7 @@ void main() { ...@@ -384,7 +386,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); // pub sets date of .packages to 2002 await pub.get(context: PubContext.flutterTests, checkLastModified: true); // 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);
...@@ -396,12 +398,44 @@ void main() { ...@@ -396,12 +398,44 @@ 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); // pub does nothing await pub.get(context: PubContext.flutterTests, checkLastModified: true); // 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();
}); });
} }
......
...@@ -24,8 +24,7 @@ final ProcessUtils processUtils = ProcessUtils(processManager: processManager, l ...@@ -24,8 +24,7 @@ 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', platform.isWindows ? 'flutter.bat' : 'flutter'); final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', '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() {
......
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