From 1fd84f88e915427c88fb1d38c052150c76e27b4f Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Mon, 13 Mar 2023 08:38:17 +0100 Subject: [PATCH] Always use user-level pub cache (#121802) Use the pub cache resolved by pub itself. To add packages to the flutter.zip download they are packaged as tar.gz and added to the pub-cache on first run by using `pub cache preload`. --- .gitignore | 2 +- bin/internal/shared.bat | 2 - bin/internal/shared.sh | 3 - dev/bots/prepare_package.dart | 108 +++++++++++- dev/bots/test/prepare_package_test.dart | 5 + packages/flutter_tools/lib/src/dart/pub.dart | 156 ++++-------------- .../base/pub_join_caches_test.dart | 97 ----------- .../test/general.shard/dart/pub_get_test.dart | 43 ++--- 8 files changed, 160 insertions(+), 256 deletions(-) delete mode 100644 packages/flutter_tools/test/general.shard/base/pub_join_caches_test.dart diff --git a/.gitignore b/.gitignore index 04394df971..ad69aadb26 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,7 @@ analysis_benchmark.json .flutter-plugins-dependencies **/generated_plugin_registrant.dart .packages -.pub-cache/ +.pub-preload-cache/ .pub/ build/ flutter_*.png diff --git a/bin/internal/shared.bat b/bin/internal/shared.bat index ca372a4897..0599ab084c 100644 --- a/bin/internal/shared.bat +++ b/bin/internal/shared.bat @@ -22,8 +22,6 @@ SET script_path=%flutter_tools_dir%\bin\flutter_tools.dart SET dart_sdk_path=%cache_dir%\dart-sdk SET engine_stamp=%cache_dir%\engine-dart-sdk.stamp SET engine_version_path=%FLUTTER_ROOT%\bin\internal\engine.version -SET pub_cache_path=%FLUTTER_ROOT%\.pub-cache - SET dart=%dart_sdk_path%\bin\dart.exe REM Ensure that bin/cache exists. diff --git a/bin/internal/shared.sh b/bin/internal/shared.sh index c509934d6f..a38dd3556c 100644 --- a/bin/internal/shared.sh +++ b/bin/internal/shared.sh @@ -149,9 +149,6 @@ function upgrade_flutter () ( export PUB_SUMMARY_ONLY=1 fi export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install" - if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then - export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}" - fi pub_upgrade_with_retry # Move the old snapshot - we can't just overwrite it as the VM might currently have it diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart index 85034e5742..cfece5bc84 100644 --- a/dev/bots/prepare_package.dart +++ b/dev/bots/prepare_package.dart @@ -8,11 +8,13 @@ import 'dart:io' hide Platform; import 'dart:typed_data'; import 'package:args/args.dart'; +import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart'; import 'package:crypto/src/digest_sink.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; import 'package:platform/platform.dart' show LocalPlatform, Platform; +import 'package:pool/pool.dart'; import 'package:process/process.dart'; const String gobMirror = @@ -189,7 +191,7 @@ class ArchiveCreator { subprocessOutput: subprocessOutput, platform: platform, )..environment['PUB_CACHE'] = path.join( - flutterRoot.absolute.path, '.pub-cache', + tempDir.path, '.pub-cache', ); final String flutterExecutable = path.join( flutterRoot.absolute.path, @@ -426,6 +428,104 @@ class ArchiveCreator { await _unzipArchive(gitFile, workingDirectory: minGitPath); } + /// Downloads an archive of every package that is present in the temporary + /// pub-cache from pub.dev. Stores the archives in + /// $flutterRoot/.pub-preload-cache. + /// + /// These archives will be installed in the user-level cache on first + /// following flutter command that accesses the cache. + /// + /// Precondition: all packages currently in the PUB_CACHE of [_processRunner] + /// are installed from pub.dev. + Future _downloadPubPackageArchives() async { + final Pool pool = Pool(10); // Number of simultaneous downloads. + final http.Client client = http.Client(); + final Directory preloadCache = Directory(path.join(flutterRoot.path, '.pub-preload-cache')); + preloadCache.createSync(recursive: true); + /// Fetch a single package. + Future fetchPackageArchive(String name, String version) async { + await pool.withResource(() async { + stderr.write('Fetching package archive for $name-$version.\n'); + int retries = 7; + while (true) { + retries-=1; + try { + final Uri packageListingUrl = + Uri.parse('https://pub.dev/api/packages/$name'); + // Fetch the package listing to obtain the package download url. + final http.Response packageListingResponse = + await client.get(packageListingUrl); + if (packageListingResponse.statusCode != 200) { + throw Exception('Downloading $packageListingUrl failed. Status code ${packageListingResponse.statusCode}.'); + } + final dynamic decodedPackageListing = json.decode(packageListingResponse.body); + if (decodedPackageListing is! Map) { + throw const FormatException('Package listing should be a map'); + } + final dynamic versions = decodedPackageListing['versions']; + if (versions is! List) { + throw const FormatException('.versions should be a list'); + } + final Map versionDescription = versions.firstWhere( + (dynamic description) { + if (description is! Map) { + throw const FormatException('.versions elements should be maps'); + } + return description['version'] == version; + }, + orElse: () => throw FormatException('Could not find $name-$version in package listing') + ) as Map; + final dynamic downloadUrl = versionDescription['archive_url']; + if (downloadUrl is! String) { + throw const FormatException('archive_url should be a string'); + } + final dynamic archiveSha256 = versionDescription['archive_sha256']; + if (archiveSha256 is! String) { + throw const FormatException('archive_sha256 should be a string'); + } + final http.Request request = http.Request('get', Uri.parse(downloadUrl)); + final http.StreamedResponse response = await client.send(request); + if (response.statusCode != 200) { + throw Exception('Downloading ${request.url} failed. Status code ${response.statusCode}.'); + } + final File archiveFile = File( + path.join(preloadCache.path, '$name-$version.tar.gz'), + ); + await response.stream.pipe(archiveFile.openWrite()); + final Stream> archiveStream = archiveFile.openRead(); + final Digest r = await sha256.bind(archiveStream).first; + if (hex.encode(r.bytes) != archiveSha256) { + throw Exception('Hash mismatch of downloaded archive'); + } + } on Exception catch (e) { + stderr.write('Failed downloading $name-$version. $e\n'); + if (retries > 0) { + stderr.write('Retrying download of $name-$version...'); + // Retry. + continue; + } else { + rethrow; + } + } + break; + } + }); + } + final Map cacheDescription = + json.decode(await _runFlutter(['pub', 'cache', 'list'])) as Map; + final Map packages = cacheDescription['packages'] as Map; + final List> downloads = >[]; + for (final MapEntry package in packages.entries) { + final String name = package.key; + final Map versions = package.value as Map; + for (final String version in versions.keys) { + downloads.add(fetchPackageArchive(name, version)); + } + } + await Future.wait(downloads); + client.close(); + } + /// Prepare the archive repo so that it has all of the caches warmed up and /// is configured for the user to begin working. Future _populateCaches() async { @@ -446,7 +546,7 @@ class ArchiveCreator { workingDirectory: tempDir, ); } - + await _downloadPubPackageArchives(); // Yes, we could just skip all .packages files when constructing // the archive, but some are checked in, and we don't want to skip // those. @@ -795,8 +895,8 @@ class ArchivePublisher { } } -/// Prepares a flutter git repo to be packaged up for distribution. -/// It mainly serves to populate the .pub-cache with any appropriate Dart +/// Prepares a flutter git repo to be packaged up for distribution. It mainly +/// serves to populate the .pub-preload-cache with any appropriate Dart /// packages, and the flutter cache in bin/cache with the appropriate /// dependencies and snapshots. /// diff --git a/dev/bots/test/prepare_package_test.dart b/dev/bots/test/prepare_package_test.dart index 611764241a..e8e5cac08f 100644 --- a/dev/bots/test/prepare_package_test.dart +++ b/dev/bots/test/prepare_package_test.dart @@ -143,6 +143,7 @@ void main() { '$flutter create --template=app ${createBase}app': null, '$flutter create --template=package ${createBase}package': null, '$flutter create --template=plugin ${createBase}plugin': null, + '$flutter pub cache list': [ProcessResult(0,0,'{"packages":{}}','')], 'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.dart_tool/': null, if (platform.isMacOS) 'codesign -vvvv --check-notarization ${path.join(tempDir.path, 'flutter', 'bin', 'cache', 'dart-sdk', 'bin', 'dart')}': null, @@ -180,6 +181,7 @@ void main() { '$flutter create --template=app ${createBase}app': null, '$flutter create --template=package ${createBase}package': null, '$flutter create --template=plugin ${createBase}plugin': null, + '$flutter pub cache list': [ProcessResult(0,0,'{"packages":{}}','')], 'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.dart_tool/': null, if (platform.isMacOS) 'codesign -vvvv --check-notarization ${path.join(tempDir.path, 'flutter', 'bin', 'cache', 'dart-sdk', 'bin', 'dart')}': null, @@ -228,6 +230,7 @@ void main() { '$flutter create --template=app ${createBase}app': null, '$flutter create --template=package ${createBase}package': null, '$flutter create --template=plugin ${createBase}plugin': null, + '$flutter pub cache list': [ProcessResult(0,0,'{"packages":{}}','')], 'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.dart_tool/': null, if (platform.isMacOS) 'codesign -vvvv --check-notarization ${path.join(tempDir.path, 'flutter', 'bin', 'cache', 'dart-sdk', 'bin', 'dart')}': null, @@ -286,6 +289,7 @@ void main() { '$flutter create --template=app ${createBase}app': null, '$flutter create --template=package ${createBase}package': null, '$flutter create --template=plugin ${createBase}plugin': null, + '$flutter pub cache list': [ProcessResult(0,0,'{"packages":{}}','')], 'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.dart_tool/': null, if (platform.isWindows) 'attrib -h .git': null, @@ -336,6 +340,7 @@ void main() { '$flutter create --template=app ${createBase}app': null, '$flutter create --template=package ${createBase}package': null, '$flutter create --template=plugin ${createBase}plugin': null, + '$flutter pub cache list': [ProcessResult(0,0,'{"packages":{}}','')], 'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.dart_tool/': null, if (platform.isMacOS) 'codesign -vvvv --check-notarization $binPath': [codesignFailure], diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 06d4000201..a7e513a8d5 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -34,39 +34,29 @@ const String _kPubCacheEnvironmentKey = 'PUB_CACHE'; typedef MessageFilter = String? Function(String message); -/// globalCachePath is the directory in which the content of the localCachePath will be moved in -void joinCaches({ - required FileSystem fileSystem, - required Directory globalCacheDirectory, - required Directory dependencyDirectory, +/// Load any package-files stored in [preloadCacheDir] into the pub cache if it +/// exists. +/// +/// Deletes the [preloadCacheDir]. +@visibleForTesting +void preloadPubCache({ + required Directory preloadCacheDir, + required ProcessManager processManager, + required Logger logger, + required List pubCommand, }) { - for (final FileSystemEntity entity in dependencyDirectory.listSync()) { - final String newPath = fileSystem.path.join(globalCacheDirectory.path, entity.basename); - if (entity is File) { - if (!fileSystem.file(newPath).existsSync()) { - entity.copySync(newPath); - } - } else if (entity is Directory) { - if (!globalCacheDirectory.childDirectory(entity.basename).existsSync()) { - final Directory newDirectory = globalCacheDirectory.childDirectory(entity.basename); - newDirectory.createSync(); - joinCaches( - fileSystem: fileSystem, - globalCacheDirectory: newDirectory, - dependencyDirectory: entity, - ); - } - } + if (preloadCacheDir.existsSync()) { + final Iterable cacheFiles = + preloadCacheDir + .listSync() + .map((FileSystemEntity f) => f.path) + .where((String path) => path.endsWith('.tar.gz')); + processManager.runSync([...pubCommand, 'cache', 'preload',...cacheFiles]); + _tryDeleteDirectory(preloadCacheDir, logger); } } -Directory createDependencyDirectory(Directory pubGlobalDirectory, String dependencyName) { - final Directory newDirectory = pubGlobalDirectory.childDirectory(dependencyName); - newDirectory.createSync(); - return newDirectory; -} - -bool tryDelete(Directory directory, Logger logger) { +bool _tryDeleteDirectory(Directory directory, Logger logger) { try { if (directory.existsSync()) { directory.deleteSync(recursive: true); @@ -78,24 +68,6 @@ bool tryDelete(Directory directory, Logger logger) { return true; } -/// When local cache (flutter_root/.pub-cache) and global cache (HOME/.pub-cache) are present a -/// merge needs to be done leaving only the global -/// -/// Valid pubCache should look like this ./localCachePath/.pub-cache/hosted/pub.dartlang.org -bool needsToJoinCache({ - required FileSystem fileSystem, - required String localCachePath, - required Directory? globalDirectory, -}) { - if (globalDirectory == null) { - return false; - } - final Directory localDirectory = fileSystem.directory(localCachePath); - - return globalDirectory.childDirectory('hosted').childDirectory('pub.dartlang.org').existsSync() && - localDirectory.childDirectory('hosted').childDirectory('pub.dartlang.org').existsSync(); -} - /// Represents Flutter-specific data that is added to the `PUB_ENVIRONMENT` /// environment variable and allows understanding the type of requests made to /// the package site on Flutter's behalf. @@ -402,7 +374,7 @@ class _DefaultPub implements Pub { }) async { int exitCode; - final List pubCommand = _pubCommand(arguments); + final List pubCommand = [..._pubCommand, ...arguments]; final Map pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride, summaryOnly: outputMode == PubOutputMode.summaryOnly); try { @@ -536,7 +508,7 @@ class _DefaultPub implements Pub { arguments.insert(0, '--trace'); } final Map pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride); - final List pubCommand = _pubCommand(arguments); + final List pubCommand = [..._pubCommand, ...arguments]; final int code = await _processUtils.stream( pubCommand, workingDirectory: directory, @@ -590,7 +562,9 @@ class _DefaultPub implements Pub { } /// The command used for running pub. - List _pubCommand(List arguments) { + late final List _pubCommand = _computePubCommand(); + + List _computePubCommand() { // TODO(zanderso): refactor to use artifacts. final String sdkPath = _fileSystem.path.joinAll([ Cache.flutterRoot!, @@ -607,7 +581,7 @@ class _DefaultPub implements Pub { 'permissions for the current user.' ); } - return [sdkPath, '--no-analytics', 'pub', ...arguments]; + return [sdkPath, '--no-analytics', 'pub']; } // Returns the environment value that should be used when running pub. @@ -629,88 +603,26 @@ class _DefaultPub implements Pub { return values.join(':'); } - /// There are 3 ways to get the pub cache location + /// There are 2 ways to get the pub cache location /// /// 1) Provide the _kPubCacheEnvironmentKey. - /// 2) There is a local cache (in the Flutter SDK) but not a global one (in the user's home directory). - /// 3) If both local and global are available then merge the local into global and return the global. + /// 2) The pub default user-level pub cache. + /// + /// If we are using 2, check if there are pre-packaged packages in + /// $FLUTTER_ROOT/.pub-preload-cache and install them in the user-level cache. String? _getPubCacheIfAvailable() { if (_platform.environment.containsKey(_kPubCacheEnvironmentKey)) { return _platform.environment[_kPubCacheEnvironmentKey]; } - final String localCachePath = _fileSystem.path.join(Cache.flutterRoot!, '.pub-cache'); - final Directory? globalDirectory; - if (_platform.isWindows) { - globalDirectory = _getWindowsGlobalDirectory; - } - else { - if (_platform.environment['HOME'] == null) { - globalDirectory = null; - } else { - final String homeDirectoryPath = _platform.environment['HOME']!; - globalDirectory = _fileSystem.directory(_fileSystem.path.join(homeDirectoryPath, '.pub-cache')); - } - } - - if (needsToJoinCache( - fileSystem: _fileSystem, - localCachePath: localCachePath, - globalDirectory: globalDirectory, - )) { - final Directory localDirectoryPub = _fileSystem.directory( - _fileSystem.path.join(localCachePath, 'hosted', 'pub.dartlang.org') - ); - final Directory globalDirectoryPub = _fileSystem.directory( - _fileSystem.path.join(globalDirectory!.path, 'hosted', 'pub.dartlang.org') - ); - for (final FileSystemEntity entity in localDirectoryPub.listSync()) { - if (entity is Directory && !globalDirectoryPub.childDirectory(entity.basename).existsSync()){ - try { - final Directory newDirectory = createDependencyDirectory(globalDirectoryPub, entity.basename); - joinCaches( - fileSystem: _fileSystem, - globalCacheDirectory: newDirectory, - dependencyDirectory: entity, - ); - } on FileSystemException { - if (!tryDelete(globalDirectoryPub.childDirectory(entity.basename), _logger)) { - _logger.printWarning('The join of pub-caches failed'); - _logger.printStatus('Running "dart pub cache repair"'); - _processManager.runSync(['dart', 'pub', 'cache', 'repair']); - } - } - } - } - tryDelete(_fileSystem.directory(localCachePath), _logger); - return globalDirectory.path; - } else if (globalDirectory != null && globalDirectory.existsSync()) { - return globalDirectory.path; - } else if (_fileSystem.directory(localCachePath).existsSync()) { - return localCachePath; - } + final String flutterRootPath = Cache.flutterRoot!; + final Directory flutterRoot = _fileSystem.directory(flutterRootPath); + final Directory preloadCacheDir = flutterRoot.childDirectory('.pub-preload-cache'); + preloadPubCache(preloadCacheDir: preloadCacheDir,logger: _logger,processManager: _processManager, pubCommand: _pubCommand); // Use pub's default location by returning null. return null; } - Directory? get _getWindowsGlobalDirectory { - // %LOCALAPPDATA% is preferred as the cache location over %APPDATA%, because the latter is synchronised between - // devices when the user roams between them, whereas the former is not. - // The default cache dir used to be in %APPDATA%, so to avoid breaking old installs, - // we use the old dir in %APPDATA% if it exists. Else, we use the new default location - // in %LOCALAPPDATA%. - for (final String envVariable in ['APPDATA', 'LOCALAPPDATA']) { - if (_platform.environment[envVariable] != null) { - final String homePath = _platform.environment[envVariable]!; - final Directory globalDirectory = _fileSystem.directory(_fileSystem.path.join(homePath, 'Pub', 'Cache')); - if (globalDirectory.existsSync()) { - return globalDirectory; - } - } - } - return null; - } - /// The full environment used when running pub. /// /// [context] provides extra information to package server requests to diff --git a/packages/flutter_tools/test/general.shard/base/pub_join_caches_test.dart b/packages/flutter_tools/test/general.shard/base/pub_join_caches_test.dart deleted file mode 100644 index 15dee14bc5..0000000000 --- a/packages/flutter_tools/test/general.shard/base/pub_join_caches_test.dart +++ /dev/null @@ -1,97 +0,0 @@ -// 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:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/dart/pub.dart'; - -import '../../src/common.dart'; - -void main() { - testWithoutContext('join two folders', () async { - final MemoryFileSystem fileSystem = MemoryFileSystem(); - final Directory target = fileSystem.currentDirectory.childDirectory('target'); - final Directory extra = fileSystem.currentDirectory.childDirectory('extra'); - target.createSync(); - target.childFile('first.file').createSync(); - target.childDirectory('dir').createSync(); - - extra.createSync(); - extra.childFile('second.file').writeAsBytesSync([0]); - extra.childDirectory('dir').createSync(); - extra.childDirectory('dir').childFile('third.file').writeAsBytesSync([0]); - extra.childDirectory('dir_2').createSync(); - extra.childDirectory('dir_2').childFile('fourth.file').writeAsBytesSync([0]); - extra.childDirectory('dir_3').createSync(); - extra.childDirectory('dir_3').childFile('fifth.file').writeAsBytesSync([0]); - joinCaches( - fileSystem: fileSystem, - globalCacheDirectory: target, - dependencyDirectory: extra, - ); - - expect(target.childFile('second.file').existsSync(), true); - expect(target.childDirectory('dir').childFile('third.file').existsSync(), false); - expect(target.childDirectory('dir_2').childFile('fourth.file').existsSync(), true); - expect(target.childDirectory('dir_3').childFile('fifth.file').existsSync(), true); - expect(extra.childDirectory('dir').childFile('third.file').existsSync(), true); - }); - - group('needsToJoinCache()', (){ - testWithoutContext('make join', () async { - final MemoryFileSystem fileSystem = MemoryFileSystem(); - final Directory local = fileSystem.currentDirectory.childDirectory('local'); - final Directory global = fileSystem.currentDirectory.childDirectory('global'); - - for (final Directory directory in [local, global]) { - directory.createSync(); - directory.childDirectory('hosted').createSync(); - directory.childDirectory('hosted').childDirectory('pub.dartlang.org').createSync(); - } - final bool pass = needsToJoinCache( - fileSystem: fileSystem, - localCachePath: local.path, - globalDirectory: global, - ); - expect(pass, true); - }); - - testWithoutContext('detects when global pub-cache does not have a pub.dartlang.org dir', () async { - final MemoryFileSystem fileSystem = MemoryFileSystem(); - final Directory local = fileSystem.currentDirectory.childDirectory('local'); - final Directory global = fileSystem.currentDirectory.childDirectory('global'); - local.createSync(); - global.createSync(); - local.childDirectory('hosted').createSync(); - local.childDirectory('hosted').childDirectory('pub.dartlang.org').createSync(); - - expect( - needsToJoinCache( - fileSystem: fileSystem, - localCachePath: local.path, - globalDirectory: global - ), - false - ); - }); - testWithoutContext("don't join global directory null", () async { - final MemoryFileSystem fileSystem = MemoryFileSystem(); - final Directory local = fileSystem.currentDirectory.childDirectory('local'); - const Directory? global = null; - local.createSync(); - local.childDirectory('hosted').createSync(); - local.childDirectory('hosted').childDirectory('pub.dartlang.org').createSync(); - - expect( - needsToJoinCache( - fileSystem: fileSystem, - localCachePath: local.path, - globalDirectory: global - ), - false - ); - }); - }); -} diff --git a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart index fb42718ae0..698fccbe18 100644 --- a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart +++ b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart @@ -757,29 +757,24 @@ exit code: 66 expect(processManager, hasNoRemainingExpectations); }); - testWithoutContext('pub cache local is merge to global', () async { + testWithoutContext('Preloaded packages are added to the pub cache', () async { final FileSystem fileSystem = MemoryFileSystem.test(); - final Directory local = fileSystem.currentDirectory.childDirectory('.pub-cache'); - final Directory global = fileSystem.currentDirectory.childDirectory('/global'); - global.createSync(); - for (final Directory dir in [global.childDirectory('.pub-cache'), local]) { - dir.createSync(); - dir.childDirectory('hosted').createSync(); - dir.childDirectory('hosted').childDirectory('pub.dartlang.org').createSync(); - } - - final Directory globalHosted = global.childDirectory('.pub-cache').childDirectory('hosted').childDirectory('pub.dartlang.org'); - globalHosted.childFile('first.file').createSync(); - globalHosted.childDirectory('dir').createSync(); - - final Directory localHosted = local.childDirectory('hosted').childDirectory('pub.dartlang.org'); - localHosted.childFile('second.file').writeAsBytesSync([0]); - localHosted.childDirectory('dir').createSync(); - localHosted.childDirectory('dir').childFile('third.file').writeAsBytesSync([0]); - localHosted.childDirectory('dir_2').createSync(); - localHosted.childDirectory('dir_2').childFile('fourth.file').writeAsBytesSync([0]); + final Directory preloadCache = fileSystem.currentDirectory.childDirectory('.pub-preload-cache'); + preloadCache.childFile('a.tar.gz').createSync(recursive: true); + preloadCache.childFile('b.tar.gz').createSync(); final FakeProcessManager processManager = FakeProcessManager.list([ + const FakeCommand( + command: [ + 'bin/cache/dart-sdk/bin/dart', + '--no-analytics', + 'pub', + 'cache', + 'preload', + '.pub-preload-cache/a.tar.gz', + '.pub-preload-cache/b.tar.gz', + ], + ), const FakeCommand( command: [ 'bin/cache/dart-sdk/bin/dart', @@ -793,7 +788,6 @@ exit code: 66 exitCode: 69, environment: { 'FLUTTER_ROOT': '', - 'PUB_CACHE': '/global/.pub-cache', 'PUB_ENVIRONMENT': 'flutter_cli:flutter_tests', }, ), @@ -822,12 +816,7 @@ exit code: 66 } expect(processManager, hasNoRemainingExpectations); - expect(local.existsSync(), false); - expect(globalHosted.childFile('second.file').existsSync(), false); - expect( - globalHosted.childDirectory('dir').childFile('third.file').existsSync(), false - ); // do not copy dependencies that are already downloaded - expect(globalHosted.childDirectory('dir_2').childFile('fourth.file').existsSync(), true); + expect(preloadCache.existsSync(), false); }); testWithoutContext('pub cache in environment is used', () async {