Unverified Commit 1fd84f88 authored by Sigurd Meldgaard's avatar Sigurd Meldgaard Committed by GitHub

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`.
parent 9ba0d08e
...@@ -51,7 +51,7 @@ analysis_benchmark.json ...@@ -51,7 +51,7 @@ analysis_benchmark.json
.flutter-plugins-dependencies .flutter-plugins-dependencies
**/generated_plugin_registrant.dart **/generated_plugin_registrant.dart
.packages .packages
.pub-cache/ .pub-preload-cache/
.pub/ .pub/
build/ build/
flutter_*.png flutter_*.png
......
...@@ -22,8 +22,6 @@ SET script_path=%flutter_tools_dir%\bin\flutter_tools.dart ...@@ -22,8 +22,6 @@ SET script_path=%flutter_tools_dir%\bin\flutter_tools.dart
SET dart_sdk_path=%cache_dir%\dart-sdk SET dart_sdk_path=%cache_dir%\dart-sdk
SET engine_stamp=%cache_dir%\engine-dart-sdk.stamp SET engine_stamp=%cache_dir%\engine-dart-sdk.stamp
SET engine_version_path=%FLUTTER_ROOT%\bin\internal\engine.version 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 SET dart=%dart_sdk_path%\bin\dart.exe
REM Ensure that bin/cache exists. REM Ensure that bin/cache exists.
......
...@@ -149,9 +149,6 @@ function upgrade_flutter () ( ...@@ -149,9 +149,6 @@ function upgrade_flutter () (
export PUB_SUMMARY_ONLY=1 export PUB_SUMMARY_ONLY=1
fi fi
export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install" 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 pub_upgrade_with_retry
# Move the old snapshot - we can't just overwrite it as the VM might currently have it # Move the old snapshot - we can't just overwrite it as the VM might currently have it
......
...@@ -8,11 +8,13 @@ import 'dart:io' hide Platform; ...@@ -8,11 +8,13 @@ import 'dart:io' hide Platform;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:crypto/src/digest_sink.dart'; import 'package:crypto/src/digest_sink.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:platform/platform.dart' show LocalPlatform, Platform; import 'package:platform/platform.dart' show LocalPlatform, Platform;
import 'package:pool/pool.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
const String gobMirror = const String gobMirror =
...@@ -189,7 +191,7 @@ class ArchiveCreator { ...@@ -189,7 +191,7 @@ class ArchiveCreator {
subprocessOutput: subprocessOutput, subprocessOutput: subprocessOutput,
platform: platform, platform: platform,
)..environment['PUB_CACHE'] = path.join( )..environment['PUB_CACHE'] = path.join(
flutterRoot.absolute.path, '.pub-cache', tempDir.path, '.pub-cache',
); );
final String flutterExecutable = path.join( final String flutterExecutable = path.join(
flutterRoot.absolute.path, flutterRoot.absolute.path,
...@@ -426,6 +428,104 @@ class ArchiveCreator { ...@@ -426,6 +428,104 @@ class ArchiveCreator {
await _unzipArchive(gitFile, workingDirectory: minGitPath); 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<void> _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<void> 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<String, dynamic> 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<String, dynamic>;
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<List<int>> 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<String, dynamic> cacheDescription =
json.decode(await _runFlutter(<String>['pub', 'cache', 'list'])) as Map<String, dynamic>;
final Map<String, dynamic> packages = cacheDescription['packages'] as Map<String, dynamic>;
final List<Future<void>> downloads = <Future<void>>[];
for (final MapEntry<String, dynamic> package in packages.entries) {
final String name = package.key;
final Map<String, dynamic> versions = package.value as Map<String, dynamic>;
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 /// Prepare the archive repo so that it has all of the caches warmed up and
/// is configured for the user to begin working. /// is configured for the user to begin working.
Future<void> _populateCaches() async { Future<void> _populateCaches() async {
...@@ -446,7 +546,7 @@ class ArchiveCreator { ...@@ -446,7 +546,7 @@ class ArchiveCreator {
workingDirectory: tempDir, workingDirectory: tempDir,
); );
} }
await _downloadPubPackageArchives();
// Yes, we could just skip all .packages files when constructing // Yes, we could just skip all .packages files when constructing
// the archive, but some are checked in, and we don't want to skip // the archive, but some are checked in, and we don't want to skip
// those. // those.
...@@ -795,8 +895,8 @@ class ArchivePublisher { ...@@ -795,8 +895,8 @@ class ArchivePublisher {
} }
} }
/// Prepares a flutter git repo to be packaged up for distribution. /// Prepares a flutter git repo to be packaged up for distribution. It mainly
/// It mainly serves to populate the .pub-cache with any appropriate Dart /// serves to populate the .pub-preload-cache with any appropriate Dart
/// packages, and the flutter cache in bin/cache with the appropriate /// packages, and the flutter cache in bin/cache with the appropriate
/// dependencies and snapshots. /// dependencies and snapshots.
/// ///
......
...@@ -143,6 +143,7 @@ void main() { ...@@ -143,6 +143,7 @@ void main() {
'$flutter create --template=app ${createBase}app': null, '$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null, '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null, '$flutter create --template=plugin ${createBase}plugin': null,
'$flutter pub cache list': <ProcessResult>[ProcessResult(0,0,'{"packages":{}}','')],
'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.packages': null,
'git clean -f -x -- **/.dart_tool/': 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, 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() { ...@@ -180,6 +181,7 @@ void main() {
'$flutter create --template=app ${createBase}app': null, '$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null, '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null, '$flutter create --template=plugin ${createBase}plugin': null,
'$flutter pub cache list': <ProcessResult>[ProcessResult(0,0,'{"packages":{}}','')],
'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.packages': null,
'git clean -f -x -- **/.dart_tool/': 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, 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() { ...@@ -228,6 +230,7 @@ void main() {
'$flutter create --template=app ${createBase}app': null, '$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null, '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null, '$flutter create --template=plugin ${createBase}plugin': null,
'$flutter pub cache list': <ProcessResult>[ProcessResult(0,0,'{"packages":{}}','')],
'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.packages': null,
'git clean -f -x -- **/.dart_tool/': 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, 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() { ...@@ -286,6 +289,7 @@ void main() {
'$flutter create --template=app ${createBase}app': null, '$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null, '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null, '$flutter create --template=plugin ${createBase}plugin': null,
'$flutter pub cache list': <ProcessResult>[ProcessResult(0,0,'{"packages":{}}','')],
'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.packages': null,
'git clean -f -x -- **/.dart_tool/': null, 'git clean -f -x -- **/.dart_tool/': null,
if (platform.isWindows) 'attrib -h .git': null, if (platform.isWindows) 'attrib -h .git': null,
...@@ -336,6 +340,7 @@ void main() { ...@@ -336,6 +340,7 @@ void main() {
'$flutter create --template=app ${createBase}app': null, '$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null, '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null, '$flutter create --template=plugin ${createBase}plugin': null,
'$flutter pub cache list': <ProcessResult>[ProcessResult(0,0,'{"packages":{}}','')],
'git clean -f -x -- **/.packages': null, 'git clean -f -x -- **/.packages': null,
'git clean -f -x -- **/.dart_tool/': null, 'git clean -f -x -- **/.dart_tool/': null,
if (platform.isMacOS) 'codesign -vvvv --check-notarization $binPath': <ProcessResult>[codesignFailure], if (platform.isMacOS) 'codesign -vvvv --check-notarization $binPath': <ProcessResult>[codesignFailure],
......
...@@ -34,39 +34,29 @@ const String _kPubCacheEnvironmentKey = 'PUB_CACHE'; ...@@ -34,39 +34,29 @@ const String _kPubCacheEnvironmentKey = 'PUB_CACHE';
typedef MessageFilter = String? Function(String message); typedef MessageFilter = String? Function(String message);
/// globalCachePath is the directory in which the content of the localCachePath will be moved in /// Load any package-files stored in [preloadCacheDir] into the pub cache if it
void joinCaches({ /// exists.
required FileSystem fileSystem, ///
required Directory globalCacheDirectory, /// Deletes the [preloadCacheDir].
required Directory dependencyDirectory, @visibleForTesting
void preloadPubCache({
required Directory preloadCacheDir,
required ProcessManager processManager,
required Logger logger,
required List<String> pubCommand,
}) { }) {
for (final FileSystemEntity entity in dependencyDirectory.listSync()) { if (preloadCacheDir.existsSync()) {
final String newPath = fileSystem.path.join(globalCacheDirectory.path, entity.basename); final Iterable<String> cacheFiles =
if (entity is File) { preloadCacheDir
if (!fileSystem.file(newPath).existsSync()) { .listSync()
entity.copySync(newPath); .map((FileSystemEntity f) => f.path)
} .where((String path) => path.endsWith('.tar.gz'));
} else if (entity is Directory) { processManager.runSync(<String>[...pubCommand, 'cache', 'preload',...cacheFiles]);
if (!globalCacheDirectory.childDirectory(entity.basename).existsSync()) { _tryDeleteDirectory(preloadCacheDir, logger);
final Directory newDirectory = globalCacheDirectory.childDirectory(entity.basename);
newDirectory.createSync();
joinCaches(
fileSystem: fileSystem,
globalCacheDirectory: newDirectory,
dependencyDirectory: entity,
);
}
}
} }
} }
Directory createDependencyDirectory(Directory pubGlobalDirectory, String dependencyName) { bool _tryDeleteDirectory(Directory directory, Logger logger) {
final Directory newDirectory = pubGlobalDirectory.childDirectory(dependencyName);
newDirectory.createSync();
return newDirectory;
}
bool tryDelete(Directory directory, Logger logger) {
try { try {
if (directory.existsSync()) { if (directory.existsSync()) {
directory.deleteSync(recursive: true); directory.deleteSync(recursive: true);
...@@ -78,24 +68,6 @@ bool tryDelete(Directory directory, Logger logger) { ...@@ -78,24 +68,6 @@ bool tryDelete(Directory directory, Logger logger) {
return true; 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` /// Represents Flutter-specific data that is added to the `PUB_ENVIRONMENT`
/// environment variable and allows understanding the type of requests made to /// environment variable and allows understanding the type of requests made to
/// the package site on Flutter's behalf. /// the package site on Flutter's behalf.
...@@ -402,7 +374,7 @@ class _DefaultPub implements Pub { ...@@ -402,7 +374,7 @@ class _DefaultPub implements Pub {
}) async { }) async {
int exitCode; int exitCode;
final List<String> pubCommand = _pubCommand(arguments); final List<String> pubCommand = <String>[..._pubCommand, ...arguments];
final Map<String, String> pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride, summaryOnly: outputMode == PubOutputMode.summaryOnly); final Map<String, String> pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride, summaryOnly: outputMode == PubOutputMode.summaryOnly);
try { try {
...@@ -536,7 +508,7 @@ class _DefaultPub implements Pub { ...@@ -536,7 +508,7 @@ class _DefaultPub implements Pub {
arguments.insert(0, '--trace'); arguments.insert(0, '--trace');
} }
final Map<String, String> pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride); final Map<String, String> pubEnvironment = await _createPubEnvironment(context: context, flutterRootOverride: flutterRootOverride);
final List<String> pubCommand = _pubCommand(arguments); final List<String> pubCommand = <String>[..._pubCommand, ...arguments];
final int code = await _processUtils.stream( final int code = await _processUtils.stream(
pubCommand, pubCommand,
workingDirectory: directory, workingDirectory: directory,
...@@ -590,7 +562,9 @@ class _DefaultPub implements Pub { ...@@ -590,7 +562,9 @@ class _DefaultPub implements Pub {
} }
/// The command used for running pub. /// The command used for running pub.
List<String> _pubCommand(List<String> arguments) { late final List<String> _pubCommand = _computePubCommand();
List<String> _computePubCommand() {
// TODO(zanderso): refactor to use artifacts. // TODO(zanderso): refactor to use artifacts.
final String sdkPath = _fileSystem.path.joinAll(<String>[ final String sdkPath = _fileSystem.path.joinAll(<String>[
Cache.flutterRoot!, Cache.flutterRoot!,
...@@ -607,7 +581,7 @@ class _DefaultPub implements Pub { ...@@ -607,7 +581,7 @@ class _DefaultPub implements Pub {
'permissions for the current user.' 'permissions for the current user.'
); );
} }
return <String>[sdkPath, '--no-analytics', 'pub', ...arguments]; return <String>[sdkPath, '--no-analytics', 'pub'];
} }
// Returns the environment value that should be used when running pub. // Returns the environment value that should be used when running pub.
...@@ -629,88 +603,26 @@ class _DefaultPub implements Pub { ...@@ -629,88 +603,26 @@ class _DefaultPub implements Pub {
return values.join(':'); 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. /// 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). /// 2) The pub default user-level pub cache.
/// 3) If both local and global are available then merge the local into global and return the global. ///
/// 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() { String? _getPubCacheIfAvailable() {
if (_platform.environment.containsKey(_kPubCacheEnvironmentKey)) { if (_platform.environment.containsKey(_kPubCacheEnvironmentKey)) {
return _platform.environment[_kPubCacheEnvironmentKey]; return _platform.environment[_kPubCacheEnvironmentKey];
} }
final String localCachePath = _fileSystem.path.join(Cache.flutterRoot!, '.pub-cache'); final String flutterRootPath = Cache.flutterRoot!;
final Directory? globalDirectory; final Directory flutterRoot = _fileSystem.directory(flutterRootPath);
if (_platform.isWindows) { final Directory preloadCacheDir = flutterRoot.childDirectory('.pub-preload-cache');
globalDirectory = _getWindowsGlobalDirectory; preloadPubCache(preloadCacheDir: preloadCacheDir,logger: _logger,processManager: _processManager, pubCommand: _pubCommand);
}
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(<String>['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;
}
// Use pub's default location by returning null. // Use pub's default location by returning null.
return 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 <String>['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. /// The full environment used when running pub.
/// ///
/// [context] provides extra information to package server requests to /// [context] provides extra information to package server requests to
......
// 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(<int>[0]);
extra.childDirectory('dir').createSync();
extra.childDirectory('dir').childFile('third.file').writeAsBytesSync(<int>[0]);
extra.childDirectory('dir_2').createSync();
extra.childDirectory('dir_2').childFile('fourth.file').writeAsBytesSync(<int>[0]);
extra.childDirectory('dir_3').createSync();
extra.childDirectory('dir_3').childFile('fifth.file').writeAsBytesSync(<int>[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 <Directory>[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
);
});
});
}
...@@ -757,29 +757,24 @@ exit code: 66 ...@@ -757,29 +757,24 @@ exit code: 66
expect(processManager, hasNoRemainingExpectations); 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 FileSystem fileSystem = MemoryFileSystem.test();
final Directory local = fileSystem.currentDirectory.childDirectory('.pub-cache'); final Directory preloadCache = fileSystem.currentDirectory.childDirectory('.pub-preload-cache');
final Directory global = fileSystem.currentDirectory.childDirectory('/global'); preloadCache.childFile('a.tar.gz').createSync(recursive: true);
global.createSync(); preloadCache.childFile('b.tar.gz').createSync();
for (final Directory dir in <Directory>[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(<int>[0]);
localHosted.childDirectory('dir').createSync();
localHosted.childDirectory('dir').childFile('third.file').writeAsBytesSync(<int>[0]);
localHosted.childDirectory('dir_2').createSync();
localHosted.childDirectory('dir_2').childFile('fourth.file').writeAsBytesSync(<int>[0]);
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
'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( const FakeCommand(
command: <String>[ command: <String>[
'bin/cache/dart-sdk/bin/dart', 'bin/cache/dart-sdk/bin/dart',
...@@ -793,7 +788,6 @@ exit code: 66 ...@@ -793,7 +788,6 @@ exit code: 66
exitCode: 69, exitCode: 69,
environment: <String, String>{ environment: <String, String>{
'FLUTTER_ROOT': '', 'FLUTTER_ROOT': '',
'PUB_CACHE': '/global/.pub-cache',
'PUB_ENVIRONMENT': 'flutter_cli:flutter_tests', 'PUB_ENVIRONMENT': 'flutter_cli:flutter_tests',
}, },
), ),
...@@ -822,12 +816,7 @@ exit code: 66 ...@@ -822,12 +816,7 @@ exit code: 66
} }
expect(processManager, hasNoRemainingExpectations); expect(processManager, hasNoRemainingExpectations);
expect(local.existsSync(), false); expect(preloadCache.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);
}); });
testWithoutContext('pub cache in environment is used', () async { testWithoutContext('pub cache in environment is used', () 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