Unverified Commit 52661bc7 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] skip copying 1GB of data from chrome cache dirs (#81170)

* [flutter_tools] skip copying 1GB of data from chrome cache dirs

* Update chrome.dart
parent b74df388
......@@ -107,10 +107,12 @@ String getDisplayPath(String fullPath, FileSystem fileSystem) {
/// source/destination file pair.
///
/// Skips files if [shouldCopyFile] returns `false`.
/// Does not recurse over directories if [shouldCopyDirectory] returns `false`.
void copyDirectory(
Directory srcDir,
Directory destDir, {
bool Function(File srcFile, File destFile)? shouldCopyFile,
bool Function(Directory)? shouldCopyDirectory,
void Function(File srcFile, File destFile)? onFileCopied,
}) {
if (!srcDir.existsSync()) {
......@@ -134,6 +136,9 @@ void copyDirectory(
newFile.writeAsBytesSync(entity.readAsBytesSync());
onFileCopied?.call(entity, newFile);
} else if (entity is Directory) {
if (shouldCopyDirectory != null && !shouldCopyDirectory(entity)) {
continue;
}
copyDirectory(
entity,
destDir.fileSystem.directory(newPath),
......
......@@ -318,13 +318,24 @@ class ChromiumLauncher {
///
/// Note: more detailed docs of the Chrome user preferences store exists here:
/// https://www.chromium.org/developers/design-documents/preferences.
///
/// This intentionally skips the Cache, Code Cache, and GPUCache directories.
/// While we're not sure exactly what is in them, this constitutes nearly 1 GB
/// of data for a fresh flutter run and adds significant overhead to all startups.
/// For workflows that may require this data, using the start-paused flag and
/// dart debug extension with a user controlled browser profile will lead to a
/// better experience.
void _cacheUserSessionInformation(Directory userDataDir, Directory cacheDir) {
final Directory targetChromeDefault = _fileSystem.directory(_fileSystem.path.join(cacheDir.path, _chromeDefaultPath));
final Directory sourceChromeDefault = _fileSystem.directory(_fileSystem.path.join(userDataDir.path, _chromeDefaultPath));
if (sourceChromeDefault.existsSync()) {
targetChromeDefault.createSync(recursive: true);
try {
copyDirectory(sourceChromeDefault, targetChromeDefault);
copyDirectory(
sourceChromeDefault,
targetChromeDefault,
shouldCopyDirectory: _isNotCacheDirectory
);
} on FileSystemException catch (err) {
// This is a best-effort update. Display the message in case the failure is relevant.
// one possible example is a file lock due to multiple running chrome instances.
......@@ -352,13 +363,24 @@ class ChromiumLauncher {
try {
if (sourceChromeDefault.existsSync()) {
targetChromeDefault.createSync(recursive: true);
copyDirectory(sourceChromeDefault, targetChromeDefault);
copyDirectory(
sourceChromeDefault,
targetChromeDefault,
shouldCopyDirectory: _isNotCacheDirectory,
);
}
} on FileSystemException catch (err) {
_logger.printError('Failed to restore Chrome preferences: $err');
}
}
// Cache, Code Cache, and GPUCache are nearly 1GB of data
bool _isNotCacheDirectory(Directory directory) {
return !directory.path.endsWith('Cache') &&
!directory.path.endsWith('Code Cache') &&
!directory.path.endsWith('GPUCache');
}
Future<Chromium> _connect(Chromium chrome, bool skipCheck) async {
// The connection is lazy. Try a simple call to make sure the provided
// connection is valid.
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:io' as io;
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
......@@ -99,6 +100,25 @@ void main() {
expect(destination.childFile('a.txt').existsSync(), isFalse);
expect(destination.childDirectory('nested').childFile('a.txt').existsSync(), isFalse);
});
testWithoutContext('Skip directories if shouldCopyDirectory returns false', () {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final Directory origin = fileSystem.directory('/origin');
origin.createSync();
fileSystem.file(fileSystem.path.join('origin', 'a.txt')).writeAsStringSync('irrelevant');
fileSystem.directory('/origin/nested').createSync();
fileSystem.file(fileSystem.path.join('origin', 'nested', 'a.txt')).writeAsStringSync('irrelevant');
fileSystem.file(fileSystem.path.join('origin', 'nested', 'b.txt')).writeAsStringSync('irrelevant');
final Directory destination = fileSystem.directory('/destination');
copyDirectory(origin, destination, shouldCopyDirectory: (Directory directory) {
return !directory.path.endsWith('nested');
});
expect(destination, exists);
expect(destination.childDirectory('nested'), isNot(exists));
expect(destination.childDirectory('nested').childFile('b.txt'),isNot(exists));
});
});
group('escapePath', () {
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
......@@ -26,6 +27,12 @@ const List<String> kChromeArgs = <String>[
'--disable-translate',
];
const List<String> kCodeCache = <String>[
'Cache',
'Code Cache',
'GPUCache',
];
const String kDevtoolsStderr = '\n\nDevTools listening\n\n';
void main() {
......@@ -351,7 +358,7 @@ void main() {
);
});
testWithoutContext('can seed chrome temp directory with existing session data', () async {
testWithoutContext('can seed chrome temp directory with existing session data, excluding Cache folder', () async {
final Completer<void> exitCompleter = Completer<void>.sync();
final Directory dataDir = fileSystem.directory('chrome-stuff');
final File preferencesFile = dataDir
......@@ -362,9 +369,16 @@ void main() {
..writeAsStringSync('"exit_type":"Crashed"');
final Directory defaultContentDirectory = dataDir
.childDirectory('Default')
.childDirectory('Foo');
defaultContentDirectory.createSync(recursive: true);
// Create Cache directories that should be skipped
for (final String cache in kCodeCache) {
dataDir
.childDirectory('Default')
.childDirectory('Foo');
defaultContentDirectory.createSync(recursive: true);
.childDirectory(cache)
.createSync(recursive: true);
}
processManager.addCommand(FakeCommand(
command: const <String>[
......@@ -397,7 +411,15 @@ void main() {
.childDirectory('Default')
.childDirectory('Foo');
expect(defaultContentDir.existsSync(), true);
expect(defaultContentDir, exists);
// Validate cache dirs are not copied.
for (final String cache in kCodeCache) {
expect(fileSystem
.directory('.tmp_rand0/flutter_tools_chrome_device.rand0')
.childDirectory('Default')
.childDirectory(cache), isNot(exists));
}
});
testWithoutContext('can retry launch when glibc bug happens', () async {
......
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