[flutter_tools] remove all globals from cache and cache_test (#69505)

This commit is contained in:
Jonah Williams 2020-11-06 15:26:45 -08:00 committed by GitHub
parent 9b201dd074
commit 2fb53d83f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 628 additions and 562 deletions

View File

@ -103,44 +103,37 @@ class Cache {
Cache({ Cache({
@protected Directory rootOverride, @protected Directory rootOverride,
@protected List<ArtifactSet> artifacts, @protected List<ArtifactSet> artifacts,
// TODO(jonahwilliams): make required once migrated to context-free. @required Logger logger,
Logger logger, @required FileSystem fileSystem,
FileSystem fileSystem, @required Platform platform,
Platform platform, @required OperatingSystemUtils osUtils,
OperatingSystemUtils osUtils,
}) : _rootOverride = rootOverride, }) : _rootOverride = rootOverride,
_logger = logger ?? globals.logger, _logger = logger,
_fileSystem = fileSystem ?? globals.fs, _fileSystem = fileSystem,
_platform = platform ?? globals.platform, _platform = platform,
_osUtils = osUtils ?? globals.os { _osUtils = osUtils,
// TODO(zra): Move to initializer list once logger and platform parameters _net = Net(logger: logger, platform: platform),
// are required. _fsUtils = FileSystemUtils(fileSystem: fileSystem, platform: platform) {
_net = Net(logger: _logger, platform: _platform);
_fsUtils = FileSystemUtils(fileSystem: _fileSystem, platform: _platform);
if (artifacts == null) { if (artifacts == null) {
_artifacts.add(MaterialFonts(this)); _artifacts.add(MaterialFonts(this));
_artifacts.add(GradleWrapper(this)); _artifacts.add(GradleWrapper(this));
_artifacts.add(AndroidMavenArtifacts(this)); _artifacts.add(AndroidGenSnapshotArtifacts(this, platform: _platform));
_artifacts.add(AndroidGenSnapshotArtifacts(this));
_artifacts.add(AndroidInternalBuildArtifacts(this)); _artifacts.add(AndroidInternalBuildArtifacts(this));
_artifacts.add(IOSEngineArtifacts(this, platform: _platform));
_artifacts.add(IOSEngineArtifacts(this));
_artifacts.add(FlutterWebSdk(this, platform: _platform)); _artifacts.add(FlutterWebSdk(this, platform: _platform));
_artifacts.add(FlutterSdk(this)); _artifacts.add(FlutterSdk(this, platform: _platform));
_artifacts.add(WindowsEngineArtifacts(this, platform: _platform)); _artifacts.add(WindowsEngineArtifacts(this, platform: _platform));
_artifacts.add(MacOSEngineArtifacts(this)); _artifacts.add(MacOSEngineArtifacts(this, platform: _platform));
_artifacts.add(LinuxEngineArtifacts(this, platform: _platform)); _artifacts.add(LinuxEngineArtifacts(this, platform: _platform));
_artifacts.add(LinuxFuchsiaSDKArtifacts(this)); _artifacts.add(LinuxFuchsiaSDKArtifacts(this, platform: _platform));
_artifacts.add(MacOSFuchsiaSDKArtifacts(this)); _artifacts.add(MacOSFuchsiaSDKArtifacts(this, platform: _platform));
_artifacts.add(FlutterRunnerSDKArtifacts(this)); _artifacts.add(FlutterRunnerSDKArtifacts(this, platform: _platform));
_artifacts.add(FlutterRunnerDebugSymbols(this, platform: _platform)); _artifacts.add(FlutterRunnerDebugSymbols(this, platform: _platform));
for (final String artifactName in IosUsbArtifacts.artifactNames) { for (final String artifactName in IosUsbArtifacts.artifactNames) {
_artifacts.add(IosUsbArtifacts(artifactName, this)); _artifacts.add(IosUsbArtifacts(artifactName, this, platform: _platform));
} }
_artifacts.add(FontSubsetArtifacts(this)); _artifacts.add(FontSubsetArtifacts(this, platform: _platform));
_artifacts.add(PubDependencies( _artifacts.add(PubDependencies(
fileSystem: _fileSystem,
logger: _logger, logger: _logger,
// flutter root and pub must be lazily initialized to avoid accessing // flutter root and pub must be lazily initialized to avoid accessing
// before the version is determined. // before the version is determined.
@ -324,19 +317,18 @@ class Cache {
/// (see [FlutterCommandRunner.runCommand]). /// (see [FlutterCommandRunner.runCommand]).
/// ///
/// This uses normal POSIX flock semantics. /// This uses normal POSIX flock semantics.
static Future<void> lock() async { Future<void> lock() async {
if (!_lockEnabled) { if (!_lockEnabled) {
return; return;
} }
assert(_lock == null); assert(_lock == null);
final File lockFile = final File lockFile =
globals.fs.file(globals.fs.path.join(flutterRoot, 'bin', 'cache', 'lockfile')); _fileSystem.file(_fileSystem.path.join(flutterRoot, 'bin', 'cache', 'lockfile'));
try { try {
_lock = lockFile.openSync(mode: FileMode.write); _lock = lockFile.openSync(mode: FileMode.write);
} on FileSystemException catch (e) { } on FileSystemException catch (e) {
globals.printError('Failed to open or create the artifact cache lockfile: "$e"'); _logger.printError('Failed to open or create the artifact cache lockfile: "$e"');
globals.printError('Please ensure you have permissions to create or open ' _logger.printError('Please ensure you have permissions to create or open ${lockFile.path}');
'${lockFile.path}');
throwToolExit('Failed to open or create the lockfile'); throwToolExit('Failed to open or create the lockfile');
} }
bool locked = false; bool locked = false;
@ -347,8 +339,8 @@ class Cache {
locked = true; locked = true;
} on FileSystemException { } on FileSystemException {
if (!printed) { if (!printed) {
globals.printTrace('Waiting to be able to obtain lock of Flutter binary artifacts directory: ${_lock.path}'); _logger.printTrace('Waiting to be able to obtain lock of Flutter binary artifacts directory: ${_lock.path}');
globals.printStatus('Waiting for another flutter command to release the startup lock...'); _logger.printStatus('Waiting for another flutter command to release the startup lock...');
printed = true; printed = true;
} }
await Future<void>.delayed(const Duration(milliseconds: 50)); await Future<void>.delayed(const Duration(milliseconds: 50));
@ -360,7 +352,7 @@ class Cache {
/// ///
/// This happens automatically on startup (see [FlutterCommand.verifyThenRunCommand]) /// This happens automatically on startup (see [FlutterCommand.verifyThenRunCommand])
/// after the command's required artifacts are updated. /// after the command's required artifacts are updated.
static void releaseLock() { void releaseLock() {
if (!_lockEnabled || _lock == null) { if (!_lockEnabled || _lock == null) {
return; return;
} }
@ -370,16 +362,15 @@ class Cache {
/// Checks if the current process owns the lock for the cache directory at /// Checks if the current process owns the lock for the cache directory at
/// this very moment; throws a [StateError] if it doesn't. /// this very moment; throws a [StateError] if it doesn't.
static void checkLockAcquired([Platform platform]) { void checkLockAcquired() {
if (_lockEnabled && _lock == null && (platform ?? globals.platform).environment['FLUTTER_ALREADY_LOCKED'] != 'true') { if (_lockEnabled && _lock == null && _platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
throw StateError( throw StateError(
'The current process does not own the lock for the cache directory. This is a bug in Flutter CLI tools.', 'The current process does not own the lock for the cache directory. This is a bug in Flutter CLI tools.',
); );
} }
} }
String _dartSdkVersion; /// The current version of Dart used to build Flutter and run the tool.
String get dartSdkVersion { String get dartSdkVersion {
if (_dartSdkVersion == null) { if (_dartSdkVersion == null) {
// Make the version string more customer-friendly. // Make the version string more customer-friendly.
@ -392,6 +383,7 @@ class Cache {
} }
return _dartSdkVersion; return _dartSdkVersion;
} }
String _dartSdkVersion;
/// The current version of the Flutter engine the flutter tool will download. /// The current version of the Flutter engine the flutter tool will download.
String get engineRevision { String get engineRevision {
@ -547,7 +539,7 @@ class Cache {
Future<bool> isUpToDate() async { Future<bool> isUpToDate() async {
for (final ArtifactSet artifact in _artifacts) { for (final ArtifactSet artifact in _artifacts) {
if (!await artifact.isUpToDate()) { if (!await artifact.isUpToDate(_fileSystem)) {
return false; return false;
} }
} }
@ -564,11 +556,11 @@ class Cache {
_logger.printTrace('Artifact $artifact is not required, skipping update.'); _logger.printTrace('Artifact $artifact is not required, skipping update.');
continue; continue;
} }
if (await artifact.isUpToDate()) { if (await artifact.isUpToDate(_fileSystem)) {
continue; continue;
} }
try { try {
await artifact.update(_artifactUpdater); await artifact.update(_artifactUpdater, _logger, _fileSystem, _osUtils);
} on SocketException catch (e) { } on SocketException catch (e) {
if (_hostsBlockedInChina.contains(e.address?.host)) { if (_hostsBlockedInChina.contains(e.address?.host)) {
_logger.printError( _logger.printError(
@ -588,15 +580,15 @@ class Cache {
bool includeAllPlatforms = true, bool includeAllPlatforms = true,
}) async { }) async {
final bool includeAllPlatformsState = this.includeAllPlatforms; final bool includeAllPlatformsState = this.includeAllPlatforms;
bool allAvailible = true; bool allAvailable = true;
this.includeAllPlatforms = includeAllPlatforms; this.includeAllPlatforms = includeAllPlatforms;
for (final ArtifactSet cachedArtifact in _artifacts) { for (final ArtifactSet cachedArtifact in _artifacts) {
if (cachedArtifact is EngineCachedArtifact) { if (cachedArtifact is EngineCachedArtifact) {
allAvailible &= await cachedArtifact.checkForArtifacts(engineVersion); allAvailable &= await cachedArtifact.checkForArtifacts(engineVersion);
} }
} }
this.includeAllPlatforms = includeAllPlatformsState; this.includeAllPlatforms = includeAllPlatformsState;
return allAvailible; return allAvailable;
} }
Future<bool> doesRemoteExist(String message, Uri url) async { Future<bool> doesRemoteExist(String message, Uri url) async {
@ -621,7 +613,7 @@ abstract class ArtifactSet {
final DevelopmentArtifact developmentArtifact; final DevelopmentArtifact developmentArtifact;
/// [true] if the artifact is up to date. /// [true] if the artifact is up to date.
Future<bool> isUpToDate(); Future<bool> isUpToDate(FileSystem fileSystem);
/// The environment variables (if any) required to consume the artifacts. /// The environment variables (if any) required to consume the artifacts.
Map<String, String> get environment { Map<String, String> get environment {
@ -629,7 +621,12 @@ abstract class ArtifactSet {
} }
/// Updates the artifact. /// Updates the artifact.
Future<void> update(ArtifactUpdater artifactUpdater); Future<void> update(
ArtifactUpdater artifactUpdater,
Logger logger,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
);
/// The canonical name of the artifact. /// The canonical name of the artifact.
String get name; String get name;
@ -665,34 +662,39 @@ abstract class CachedArtifact extends ArtifactSet {
} }
@override @override
Future<bool> isUpToDate() async { Future<bool> isUpToDate(FileSystem fileSystem) async {
if (!location.existsSync()) { if (!location.existsSync()) {
return false; return false;
} }
if (version != cache.getStampFor(stampName)) { if (version != cache.getStampFor(stampName)) {
return false; return false;
} }
return isUpToDateInner(); return isUpToDateInner(fileSystem);
} }
@override @override
Future<void> update(ArtifactUpdater artifactUpdater) async { Future<void> update(
ArtifactUpdater artifactUpdater,
Logger logger,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!location.existsSync()) { if (!location.existsSync()) {
try { try {
location.createSync(recursive: true); location.createSync(recursive: true);
} on FileSystemException catch (err) { } on FileSystemException catch (err) {
globals.printError(err.toString()); logger.printError(err.toString());
throwToolExit( throwToolExit(
'Failed to create directory for flutter cache at ${location.path}. ' 'Failed to create directory for flutter cache at ${location.path}. '
'Flutter may be missing permissions in its cache directory.' 'Flutter may be missing permissions in its cache directory.'
); );
} }
} }
await updateInner(artifactUpdater); await updateInner(artifactUpdater, fileSystem, operatingSystemUtils);
try { try {
cache.setStampFor(stampName, version); cache.setStampFor(stampName, version);
} on FileSystemException catch (err) { } on FileSystemException catch (err) {
globals.printError( logger.printError(
'The new artifact "$name" was downloaded, but Flutter failed to update ' 'The new artifact "$name" was downloaded, but Flutter failed to update '
'its stamp file, receiving the error "$err". ' 'its stamp file, receiving the error "$err". '
'Flutter can continue, but the artifact may be re-downloaded on ' 'Flutter can continue, but the artifact may be re-downloaded on '
@ -703,10 +705,13 @@ abstract class CachedArtifact extends ArtifactSet {
} }
/// Hook method for extra checks for being up-to-date. /// Hook method for extra checks for being up-to-date.
bool isUpToDateInner() => true; bool isUpToDateInner(FileSystem fileSystem) => true;
/// Template method to perform artifact update. Future<void> updateInner(
Future<void> updateInner(ArtifactUpdater artifactUpdater); ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
);
Uri _toStorageUri(String path) => Uri.parse('${cache.storageBaseUrl}/$path'); Uri _toStorageUri(String path) => Uri.parse('${cache.storageBaseUrl}/$path');
} }
@ -720,24 +725,23 @@ class PubDependencies extends ArtifactSet {
PubDependencies({ PubDependencies({
// Needs to be lazy to avoid reading from the cache before the root is initialized. // Needs to be lazy to avoid reading from the cache before the root is initialized.
@required String Function() flutterRoot, @required String Function() flutterRoot,
@required FileSystem fileSystem,
@required Logger logger, @required Logger logger,
@required Pub Function() pub, @required Pub Function() pub,
}) : _logger = logger, }) : _logger = logger,
_fileSystem = fileSystem,
_flutterRoot = flutterRoot, _flutterRoot = flutterRoot,
_pub = pub, _pub = pub,
super(DevelopmentArtifact.universal); super(DevelopmentArtifact.universal);
final String Function() _flutterRoot; final String Function() _flutterRoot;
final FileSystem _fileSystem;
final Logger _logger; final Logger _logger;
final Pub Function() _pub; final Pub Function() _pub;
@override @override
Future<bool> isUpToDate() async { Future<bool> isUpToDate(
final File toolPackageConfig = _fileSystem.file( FileSystem fileSystem,
_fileSystem.path.join(_flutterRoot(), 'packages', 'flutter_tools', kPackagesFileName), ) async {
final File toolPackageConfig = fileSystem.file(
fileSystem.path.join(_flutterRoot(), 'packages', 'flutter_tools', kPackagesFileName),
); );
if (!toolPackageConfig.existsSync()) { if (!toolPackageConfig.existsSync()) {
return false; return false;
@ -751,7 +755,7 @@ class PubDependencies extends ArtifactSet {
return false; return false;
} }
for (final Package package in packageConfig.packages) { for (final Package package in packageConfig.packages) {
if (!_fileSystem.directory(package.packageUriRoot).existsSync()) { if (!fileSystem.directory(package.packageUriRoot).existsSync()) {
return false; return false;
} }
} }
@ -762,10 +766,15 @@ class PubDependencies extends ArtifactSet {
String get name => 'pub_dependencies'; String get name => 'pub_dependencies';
@override @override
Future<void> update(ArtifactUpdater artifactUpdater) async { Future<void> update(
ArtifactUpdater artifactUpdater,
Logger logger,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
await _pub().get( await _pub().get(
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,
); );
} }
@ -780,7 +789,11 @@ class MaterialFonts extends CachedArtifact {
); );
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) { Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) {
final Uri archiveUri = _toStorageUri(version); final Uri archiveUri = _toStorageUri(version);
return artifactUpdater.downloadZipArchive('Downloading Material fonts...', archiveUri, location); return artifactUpdater.downloadZipArchive('Downloading Material fonts...', archiveUri, location);
} }
@ -791,8 +804,8 @@ class MaterialFonts extends CachedArtifact {
/// ///
/// This SDK references code within the regular Dart sdk to reduce download size. /// This SDK references code within the regular Dart sdk to reduce download size.
class FlutterWebSdk extends CachedArtifact { class FlutterWebSdk extends CachedArtifact {
FlutterWebSdk(Cache cache, {Platform platform}) FlutterWebSdk(Cache cache, {@required Platform platform})
: _platform = platform ?? globals.platform, : _platform = platform,
super( super(
'flutter_web_sdk', 'flutter_web_sdk',
cache, cache,
@ -808,7 +821,11 @@ class FlutterWebSdk extends CachedArtifact {
String get version => cache.getVersionFor('engine'); String get version => cache.getVersionFor('engine');
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
String platformName = 'flutter-web-sdk-'; String platformName = 'flutter-web-sdk-';
if (_platform.isMacOS) { if (_platform.isMacOS) {
platformName += 'darwin-x64'; platformName += 'darwin-x64';
@ -859,24 +876,24 @@ abstract class EngineCachedArtifact extends CachedArtifact {
List<String> getPackageDirs(); List<String> getPackageDirs();
@override @override
bool isUpToDateInner() { bool isUpToDateInner(FileSystem fileSystem) {
final Directory pkgDir = cache.getCacheDir('pkg'); final Directory pkgDir = cache.getCacheDir('pkg');
for (final String pkgName in getPackageDirs()) { for (final String pkgName in getPackageDirs()) {
final String pkgPath = globals.fs.path.join(pkgDir.path, pkgName); final String pkgPath = fileSystem.path.join(pkgDir.path, pkgName);
if (!globals.fs.directory(pkgPath).existsSync()) { if (!fileSystem.directory(pkgPath).existsSync()) {
return false; return false;
} }
} }
for (final List<String> toolsDir in getBinaryDirs()) { for (final List<String> toolsDir in getBinaryDirs()) {
final Directory dir = globals.fs.directory(globals.fs.path.join(location.path, toolsDir[0])); final Directory dir = fileSystem.directory(fileSystem.path.join(location.path, toolsDir[0]));
if (!dir.existsSync()) { if (!dir.existsSync()) {
return false; return false;
} }
} }
for (final String licenseDir in getLicenseDirs()) { for (final String licenseDir in getLicenseDirs()) {
final File file = globals.fs.file(globals.fs.path.join(location.path, licenseDir, 'LICENSE')); final File file = fileSystem.file(fileSystem.path.join(location.path, licenseDir, 'LICENSE'));
if (!file.existsSync()) { if (!file.existsSync()) {
return false; return false;
} }
@ -885,7 +902,11 @@ abstract class EngineCachedArtifact extends CachedArtifact {
} }
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
final String url = '${cache.storageBaseUrl}/flutter_infra/flutter/$version/'; final String url = '${cache.storageBaseUrl}/flutter_infra/flutter/$version/';
final Directory pkgDir = cache.getCacheDir('pkg'); final Directory pkgDir = cache.getCacheDir('pkg');
@ -896,28 +917,28 @@ abstract class EngineCachedArtifact extends CachedArtifact {
for (final List<String> toolsDir in getBinaryDirs()) { for (final List<String> toolsDir in getBinaryDirs()) {
final String cacheDir = toolsDir[0]; final String cacheDir = toolsDir[0];
final String urlPath = toolsDir[1]; final String urlPath = toolsDir[1];
final Directory dir = globals.fs.directory(globals.fs.path.join(location.path, cacheDir)); final Directory dir = fileSystem.directory(fileSystem.path.join(location.path, cacheDir));
// Avoid printing things like 'Downloading linux-x64 tools...' multiple times. // Avoid printing things like 'Downloading linux-x64 tools...' multiple times.
final String friendlyName = urlPath.replaceAll('/artifacts.zip', '').replaceAll('.zip', ''); final String friendlyName = urlPath.replaceAll('/artifacts.zip', '').replaceAll('.zip', '');
await artifactUpdater.downloadZipArchive('Downloading $friendlyName tools...', Uri.parse(url + urlPath), dir); await artifactUpdater.downloadZipArchive('Downloading $friendlyName tools...', Uri.parse(url + urlPath), dir);
_makeFilesExecutable(dir); _makeFilesExecutable(dir, operatingSystemUtils);
const List<String> frameworkNames = <String>['Flutter', 'FlutterMacOS']; const List<String> frameworkNames = <String>['Flutter', 'FlutterMacOS'];
for (final String frameworkName in frameworkNames) { for (final String frameworkName in frameworkNames) {
final File frameworkZip = globals.fs.file(globals.fs.path.join(dir.path, '$frameworkName.framework.zip')); final File frameworkZip = fileSystem.file(fileSystem.path.join(dir.path, '$frameworkName.framework.zip'));
if (frameworkZip.existsSync()) { if (frameworkZip.existsSync()) {
final Directory framework = globals.fs.directory(globals.fs.path.join(dir.path, '$frameworkName.framework')); final Directory framework = fileSystem.directory(fileSystem.path.join(dir.path, '$frameworkName.framework'));
framework.createSync(); framework.createSync();
globals.os.unzip(frameworkZip, framework); operatingSystemUtils.unzip(frameworkZip, framework);
} }
} }
} }
final File licenseSource = cache.getLicenseFile(); final File licenseSource = cache.getLicenseFile();
for (final String licenseDir in getLicenseDirs()) { for (final String licenseDir in getLicenseDirs()) {
final String licenseDestinationPath = globals.fs.path.join(location.path, licenseDir, 'LICENSE'); final String licenseDestinationPath = fileSystem.path.join(location.path, licenseDir, 'LICENSE');
await licenseSource.copy(licenseDestinationPath); await licenseSource.copy(licenseDestinationPath);
} }
} }
@ -928,8 +949,7 @@ abstract class EngineCachedArtifact extends CachedArtifact {
bool exists = false; bool exists = false;
for (final String pkgName in getPackageDirs()) { for (final String pkgName in getPackageDirs()) {
exists = await cache.doesRemoteExist('Checking package $pkgName is available...', exists = await cache.doesRemoteExist('Checking package $pkgName is available...', Uri.parse(url + pkgName + '.zip'));
Uri.parse(url + pkgName + '.zip'));
if (!exists) { if (!exists) {
return false; return false;
} }
@ -947,16 +967,14 @@ abstract class EngineCachedArtifact extends CachedArtifact {
return true; return true;
} }
void _makeFilesExecutable(Directory dir) { void _makeFilesExecutable(Directory dir, OperatingSystemUtils operatingSystemUtils) {
globals.os.chmod(dir, 'a+r,a+x'); operatingSystemUtils.chmod(dir, 'a+r,a+x');
for (final FileSystemEntity entity in dir.listSync(recursive: true)) { for (final File file in dir.listSync(recursive: true).whereType<File>()) {
if (entity is File) { final FileStat stat = file.statSync();
final FileStat stat = entity.statSync(); final bool isUserExecutable = ((stat.mode >> 6) & 0x1) == 1;
final bool isUserExecutable = ((stat.mode >> 6) & 0x1) == 1; if (file.basename == 'flutter_tester' || isUserExecutable) {
if (entity.basename == 'flutter_tester' || isUserExecutable) { // Make the file readable and executable by all users.
// Make the file readable and executable by all users. operatingSystemUtils.chmod(file, 'a+r,a+x');
globals.os.chmod(entity, 'a+r,a+x');
}
} }
} }
} }
@ -964,11 +982,16 @@ abstract class EngineCachedArtifact extends CachedArtifact {
/// A cached artifact containing the dart:ui source code. /// A cached artifact containing the dart:ui source code.
class FlutterSdk extends EngineCachedArtifact { class FlutterSdk extends EngineCachedArtifact {
FlutterSdk(Cache cache) : super( FlutterSdk(Cache cache, {
'flutter_sdk', @required Platform platform,
cache, }) : _platform = platform,
DevelopmentArtifact.universal, super(
); 'flutter_sdk',
cache,
DevelopmentArtifact.universal,
);
final Platform _platform;
@override @override
List<String> getPackageDirs() => const <String>['sky_engine']; List<String> getPackageDirs() => const <String>['sky_engine'];
@ -983,11 +1006,11 @@ class FlutterSdk extends EngineCachedArtifact {
<String>['linux-x64', 'linux-x64/artifacts.zip'], <String>['linux-x64', 'linux-x64/artifacts.zip'],
<String>['darwin-x64', 'darwin-x64/artifacts.zip'], <String>['darwin-x64', 'darwin-x64/artifacts.zip'],
] ]
else if (globals.platform.isWindows) else if (_platform.isWindows)
<String>['windows-x64', 'windows-x64/artifacts.zip'] <String>['windows-x64', 'windows-x64/artifacts.zip']
else if (globals.platform.isMacOS) else if (_platform.isMacOS)
<String>['darwin-x64', 'darwin-x64/artifacts.zip'] <String>['darwin-x64', 'darwin-x64/artifacts.zip']
else if (globals.platform.isLinux) else if (_platform.isLinux)
<String>['linux-x64', 'linux-x64/artifacts.zip'], <String>['linux-x64', 'linux-x64/artifacts.zip'],
]; ];
} }
@ -997,18 +1020,23 @@ class FlutterSdk extends EngineCachedArtifact {
} }
class MacOSEngineArtifacts extends EngineCachedArtifact { class MacOSEngineArtifacts extends EngineCachedArtifact {
MacOSEngineArtifacts(Cache cache) : super( MacOSEngineArtifacts(Cache cache, {
'macos-sdk', @required Platform platform,
cache, }) : _platform = platform,
DevelopmentArtifact.macOS, super(
); 'macos-sdk',
cache,
DevelopmentArtifact.macOS,
);
final Platform _platform;
@override @override
List<String> getPackageDirs() => const <String>[]; List<String> getPackageDirs() => const <String>[];
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
if (globals.platform.isMacOS || ignorePlatformFiltering) { if (_platform.isMacOS || ignorePlatformFiltering) {
return _macOSDesktopBinaryDirs; return _macOSDesktopBinaryDirs;
} }
return const <List<String>>[]; return const <List<String>>[];
@ -1076,11 +1104,16 @@ class LinuxEngineArtifacts extends EngineCachedArtifact {
/// The artifact used to generate snapshots for Android builds. /// The artifact used to generate snapshots for Android builds.
class AndroidGenSnapshotArtifacts extends EngineCachedArtifact { class AndroidGenSnapshotArtifacts extends EngineCachedArtifact {
AndroidGenSnapshotArtifacts(Cache cache) : super( AndroidGenSnapshotArtifacts(Cache cache, {
'android-sdk', @required Platform platform,
cache, }) : _platform = platform,
DevelopmentArtifact.androidGenSnapshot, super(
); 'android-sdk',
cache,
DevelopmentArtifact.androidGenSnapshot,
);
final Platform _platform;
@override @override
List<String> getPackageDirs() => const <String>[]; List<String> getPackageDirs() => const <String>[];
@ -1093,11 +1126,11 @@ class AndroidGenSnapshotArtifacts extends EngineCachedArtifact {
..._linuxBinaryDirs, ..._linuxBinaryDirs,
..._windowsBinaryDirs, ..._windowsBinaryDirs,
..._dartSdks, ..._dartSdks,
] else if (globals.platform.isWindows) ] else if (_platform.isWindows)
..._windowsBinaryDirs ..._windowsBinaryDirs
else if (globals.platform.isMacOS) else if (_platform.isMacOS)
..._osxBinaryDirs ..._osxBinaryDirs
else if (globals.platform.isLinux) else if (_platform.isLinux)
..._linuxBinaryDirs, ..._linuxBinaryDirs,
]; ];
} }
@ -1106,6 +1139,64 @@ class AndroidGenSnapshotArtifacts extends EngineCachedArtifact {
List<String> getLicenseDirs() { return <String>[]; } List<String> getLicenseDirs() { return <String>[]; }
} }
/// A cached artifact containing the Maven dependencies used to build Android projects.
class AndroidMavenArtifacts extends ArtifactSet {
AndroidMavenArtifacts(this.cache, {
@required Platform platform,
}) : _platform = platform,
super(DevelopmentArtifact.androidMaven);
final Platform _platform;
final Cache cache;
@override
Future<void> update(
ArtifactUpdater artifactUpdater,
Logger logger,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
final Directory tempDir = cache.getRoot().createTempSync(
'flutter_gradle_wrapper.',
);
gradleUtils.injectGradleWrapperIfNeeded(tempDir);
final Status status = logger.startProgress('Downloading Android Maven dependencies...');
final File gradle = tempDir.childFile(
_platform.isWindows ? 'gradlew.bat' : 'gradlew',
);
try {
final String gradleExecutable = gradle.absolute.path;
final String flutterSdk = globals.fsUtils.escapePath(Cache.flutterRoot);
final RunResult processResult = await globals.processUtils.run(
<String>[
gradleExecutable,
'-b', globals.fs.path.join(flutterSdk, 'packages', 'flutter_tools', 'gradle', 'resolve_dependencies.gradle'),
'--project-cache-dir', tempDir.path,
'resolveDependencies',
],
environment: gradleEnvironment);
if (processResult.exitCode != 0) {
logger.printError('Failed to download the Android dependencies');
}
} finally {
status.stop();
tempDir.deleteSync(recursive: true);
}
}
@override
Future<bool> isUpToDate(FileSystem fileSystem) async {
// The dependencies are downloaded and cached by Gradle.
// The tool doesn't know if the dependencies are already cached at this point.
// Therefore, call Gradle to figure this out.
return false;
}
@override
String get name => 'android-maven-artifacts';
}
/// Artifacts used for internal builds. The flutter tool builds Android projects /// Artifacts used for internal builds. The flutter tool builds Android projects
/// using the artifacts cached by [AndroidMavenArtifacts]. /// using the artifacts cached by [AndroidMavenArtifacts].
class AndroidInternalBuildArtifacts extends EngineCachedArtifact { class AndroidInternalBuildArtifacts extends EngineCachedArtifact {
@ -1127,73 +1218,29 @@ class AndroidInternalBuildArtifacts extends EngineCachedArtifact {
List<String> getLicenseDirs() { return <String>[]; } List<String> getLicenseDirs() { return <String>[]; }
} }
/// A cached artifact containing the Maven dependencies used to build Android projects.
class AndroidMavenArtifacts extends ArtifactSet {
AndroidMavenArtifacts(this.cache) : super(DevelopmentArtifact.androidMaven);
final Cache cache;
@override
Future<void> update(ArtifactUpdater artifactUpdater) async {
final Directory tempDir = cache.getRoot().createTempSync(
'flutter_gradle_wrapper.',
);
gradleUtils.injectGradleWrapperIfNeeded(tempDir);
final Status status = globals.logger.startProgress('Downloading Android Maven dependencies...');
final File gradle = tempDir.childFile(
globals.platform.isWindows ? 'gradlew.bat' : 'gradlew',
);
try {
final String gradleExecutable = gradle.absolute.path;
final String flutterSdk = globals.fsUtils.escapePath(Cache.flutterRoot);
final RunResult processResult = await globals.processUtils.run(
<String>[
gradleExecutable,
'-b', globals.fs.path.join(flutterSdk, 'packages', 'flutter_tools', 'gradle', 'resolve_dependencies.gradle'),
'--project-cache-dir', tempDir.path,
'resolveDependencies',
],
environment: gradleEnvironment);
if (processResult.exitCode != 0) {
globals.printError('Failed to download the Android dependencies');
}
} finally {
status.stop();
tempDir.deleteSync(recursive: true);
}
}
@override
Future<bool> isUpToDate() async {
// The dependencies are downloaded and cached by Gradle.
// The tool doesn't know if the dependencies are already cached at this point.
// Therefore, call Gradle to figure this out.
return false;
}
@override
String get name => 'android-maven-artifacts';
}
class IOSEngineArtifacts extends EngineCachedArtifact { class IOSEngineArtifacts extends EngineCachedArtifact {
IOSEngineArtifacts(Cache cache) : super( IOSEngineArtifacts(Cache cache, {
'ios-sdk', @required Platform platform,
cache, }) : _platform = platform,
DevelopmentArtifact.iOS, super(
); 'ios-sdk',
cache,
DevelopmentArtifact.iOS,
);
final Platform _platform;
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
return <List<String>>[ return <List<String>>[
if (globals.platform.isMacOS || ignorePlatformFiltering) if (_platform.isMacOS || ignorePlatformFiltering)
..._iosBinaryDirs, ..._iosBinaryDirs,
]; ];
} }
@override @override
List<String> getLicenseDirs() { List<String> getLicenseDirs() {
if (globals.platform.isMacOS || ignorePlatformFiltering) { if (_platform.isMacOS || ignorePlatformFiltering) {
return const <String>['ios', 'ios-profile', 'ios-release']; return const <String>['ios', 'ios-profile', 'ios-release'];
} }
return const <String>[]; return const <String>[];
@ -1218,32 +1265,36 @@ class GradleWrapper extends CachedArtifact {
List<String> get _gradleScripts => <String>['gradlew', 'gradlew.bat']; List<String> get _gradleScripts => <String>['gradlew', 'gradlew.bat'];
String get _gradleWrapper => globals.fs.path.join('gradle', 'wrapper', 'gradle-wrapper.jar');
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) { Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
final Uri archiveUri = _toStorageUri(version); final Uri archiveUri = _toStorageUri(version);
return artifactUpdater.downloadZippedTarball('Downloading Gradle Wrapper...', archiveUri, location).then<void>((_) { await artifactUpdater.downloadZippedTarball('Downloading Gradle Wrapper...', archiveUri, location);
// Delete property file, allowing templates to provide it. // Delete property file, allowing templates to provide it.
globals.fs.file(globals.fs.path.join(location.path, 'gradle', 'wrapper', 'gradle-wrapper.properties')).deleteSync(); fileSystem.file(fileSystem.path.join(location.path, 'gradle', 'wrapper', 'gradle-wrapper.properties')).deleteSync();
// Remove NOTICE file. Should not be part of the template. // Remove NOTICE file. Should not be part of the template.
globals.fs.file(globals.fs.path.join(location.path, 'NOTICE')).deleteSync(); fileSystem.file(fileSystem.path.join(location.path, 'NOTICE')).deleteSync();
});
} }
@override @override
bool isUpToDateInner() { bool isUpToDateInner(
final Directory wrapperDir = cache.getCacheDir(globals.fs.path.join('artifacts', 'gradle_wrapper')); FileSystem fileSystem,
if (!globals.fs.directory(wrapperDir).existsSync()) { ) {
final String gradleWrapper = fileSystem.path.join('gradle', 'wrapper', 'gradle-wrapper.jar');
final Directory wrapperDir = cache.getCacheDir(fileSystem.path.join('artifacts', 'gradle_wrapper'));
if (!fileSystem.directory(wrapperDir).existsSync()) {
return false; return false;
} }
for (final String scriptName in _gradleScripts) { for (final String scriptName in _gradleScripts) {
final File scriptFile = globals.fs.file(globals.fs.path.join(wrapperDir.path, scriptName)); final File scriptFile = fileSystem.file(fileSystem.path.join(wrapperDir.path, scriptName));
if (!scriptFile.existsSync()) { if (!scriptFile.existsSync()) {
return false; return false;
} }
} }
final File gradleWrapperJar = globals.fs.file(globals.fs.path.join(wrapperDir.path, _gradleWrapper)); final File gradleWrapperJar = fileSystem.file(fileSystem.path.join(wrapperDir.path, gradleWrapper));
if (!gradleWrapperJar.existsSync()) { if (!gradleWrapperJar.existsSync()) {
return false; return false;
} }
@ -1251,8 +1302,7 @@ class GradleWrapper extends CachedArtifact {
} }
} }
const String _cipdBaseUrl = const String _cipdBaseUrl = 'https://chrome-infra-packages.appspot.com/dl';
'https://chrome-infra-packages.appspot.com/dl';
/// Common functionality for pulling Fuchsia SDKs. /// Common functionality for pulling Fuchsia SDKs.
abstract class _FuchsiaSDKArtifacts extends CachedArtifact { abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
@ -1278,11 +1328,16 @@ abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
/// The pre-built flutter runner for Fuchsia development. /// The pre-built flutter runner for Fuchsia development.
class FlutterRunnerSDKArtifacts extends CachedArtifact { class FlutterRunnerSDKArtifacts extends CachedArtifact {
FlutterRunnerSDKArtifacts(Cache cache) : super( FlutterRunnerSDKArtifacts(Cache cache, {
'flutter_runner', @required Platform platform,
cache, }) : _platform = platform,
DevelopmentArtifact.flutterRunner, super(
); 'flutter_runner',
cache,
DevelopmentArtifact.flutterRunner,
);
final Platform _platform;
@override @override
Directory get location => cache.getArtifactDirectory('flutter_runner'); Directory get location => cache.getArtifactDirectory('flutter_runner');
@ -1291,13 +1346,16 @@ class FlutterRunnerSDKArtifacts extends CachedArtifact {
String get version => cache.getVersionFor('engine'); String get version => cache.getVersionFor('engine');
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(
if (!globals.platform.isLinux && !globals.platform.isMacOS) { ArtifactUpdater artifactUpdater,
return Future<void>.value(); FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!_platform.isLinux && !_platform.isMacOS) {
return;
} }
final String url = '$_cipdBaseUrl/flutter/fuchsia/+/git_revision:$version'; final String url = '$_cipdBaseUrl/flutter/fuchsia/+/git_revision:$version';
await artifactUpdater.downloadZipArchive('Downloading package flutter runner...', await artifactUpdater.downloadZipArchive('Downloading package flutter runner...', Uri.parse(url), location);
Uri.parse(url), location);
} }
} }
@ -1349,7 +1407,11 @@ class FlutterRunnerDebugSymbols extends CachedArtifact {
} }
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!_platform.isLinux && !_platform.isMacOS) { if (!_platform.isLinux && !_platform.isMacOS) {
return; return;
} }
@ -1360,12 +1422,21 @@ class FlutterRunnerDebugSymbols extends CachedArtifact {
/// The Fuchsia core SDK for Linux. /// The Fuchsia core SDK for Linux.
class LinuxFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts { class LinuxFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts {
LinuxFuchsiaSDKArtifacts(Cache cache) : super(cache, 'linux'); LinuxFuchsiaSDKArtifacts(Cache cache, {
@required Platform platform,
}) : _platform = platform,
super(cache, 'linux');
final Platform _platform;
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) { Future<void> updateInner(
if (!globals.platform.isLinux) { ArtifactUpdater artifactUpdater,
return Future<void>.value(); FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!_platform.isLinux) {
return;
} }
return _doUpdate(artifactUpdater); return _doUpdate(artifactUpdater);
} }
@ -1373,12 +1444,21 @@ class LinuxFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts {
/// The Fuchsia core SDK for MacOS. /// The Fuchsia core SDK for MacOS.
class MacOSFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts { class MacOSFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts {
MacOSFuchsiaSDKArtifacts(Cache cache) : super(cache, 'mac'); MacOSFuchsiaSDKArtifacts(Cache cache, {
@required Platform platform,
}) : _platform = platform,
super(cache, 'mac');
final Platform _platform;
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(
if (!globals.platform.isMacOS) { ArtifactUpdater artifactUpdater,
return Future<void>.value(); FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!_platform.isMacOS) {
return;
} }
return _doUpdate(artifactUpdater); return _doUpdate(artifactUpdater);
} }
@ -1386,7 +1466,12 @@ class MacOSFuchsiaSDKArtifacts extends _FuchsiaSDKArtifacts {
/// Cached artifacts for font subsetting. /// Cached artifacts for font subsetting.
class FontSubsetArtifacts extends EngineCachedArtifact { class FontSubsetArtifacts extends EngineCachedArtifact {
FontSubsetArtifacts(Cache cache) : super(artifactName, cache, DevelopmentArtifact.universal); FontSubsetArtifacts(Cache cache, {
@required Platform platform,
}) : _platform = platform,
super(artifactName, cache, DevelopmentArtifact.universal);
final Platform _platform;
static const String artifactName = 'font-subset'; static const String artifactName = 'font-subset';
@ -1400,9 +1485,9 @@ class FontSubsetArtifacts extends EngineCachedArtifact {
if (cache.includeAllPlatforms) { if (cache.includeAllPlatforms) {
return artifacts.values.toList(); return artifacts.values.toList();
} else { } else {
final List<String> binaryDirs = artifacts[globals.platform.operatingSystem]; final List<String> binaryDirs = artifacts[_platform.operatingSystem];
if (binaryDirs == null) { if (binaryDirs == null) {
throwToolExit('Unsupported operating system: ${globals.platform.operatingSystem}'); throwToolExit('Unsupported operating system: ${_platform.operatingSystem}');
} }
return <List<String>>[binaryDirs]; return <List<String>>[binaryDirs];
} }
@ -1417,12 +1502,16 @@ class FontSubsetArtifacts extends EngineCachedArtifact {
/// Cached iOS/USB binary artifacts. /// Cached iOS/USB binary artifacts.
class IosUsbArtifacts extends CachedArtifact { class IosUsbArtifacts extends CachedArtifact {
IosUsbArtifacts(String name, Cache cache) : super( IosUsbArtifacts(String name, Cache cache, {
name, @required Platform platform,
cache, }) : _platform = platform,
// This is universal to ensure every command checks for them first super(
DevelopmentArtifact.universal, name,
); cache,
DevelopmentArtifact.universal,
);
final Platform _platform;
static const List<String> artifactNames = <String>[ static const List<String> artifactNames = <String>[
'libimobiledevice', 'libimobiledevice',
@ -1454,7 +1543,7 @@ class IosUsbArtifacts extends CachedArtifact {
} }
@override @override
bool isUpToDateInner() { bool isUpToDateInner(FileSystem fileSystem) {
final List<String> executables =_kExecutables[name]; final List<String> executables =_kExecutables[name];
if (executables == null) { if (executables == null) {
return true; return true;
@ -1468,14 +1557,18 @@ class IosUsbArtifacts extends CachedArtifact {
} }
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) { Future<void> updateInner(
if (!globals.platform.isMacOS && !ignorePlatformFiltering) { ArtifactUpdater artifactUpdater,
return Future<void>.value(); FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
if (!_platform.isMacOS && !ignorePlatformFiltering) {
return;
} }
if (location.existsSync()) { if (location.existsSync()) {
location.deleteSync(recursive: true); location.deleteSync(recursive: true);
} }
return artifactUpdater.downloadZipArchive('Downloading $name...', archiveUri, location); await artifactUpdater.downloadZipArchive('Downloading $name...', archiveUri, location);
} }
@visibleForTesting @visibleForTesting
@ -1808,7 +1901,7 @@ class ArtifactUpdater {
try { try {
file.deleteSync(); file.deleteSync();
} on FileSystemException catch (e) { } on FileSystemException catch (e) {
globals.printError('Failed to delete "${file.path}". Please delete manually. $e'); _logger.printError('Failed to delete "${file.path}". Please delete manually. $e');
continue; continue;
} }
for (Directory directory = file.parent; directory.absolute.path != _tempStorage.absolute.path; directory = directory.parent) { for (Directory directory = file.parent; directory.absolute.path != _tempStorage.absolute.path; directory = directory.parent) {

View File

@ -130,7 +130,7 @@ class PrecacheCommand extends FlutterCommand {
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
// Re-lock the cache. // Re-lock the cache.
if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') { if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await Cache.lock(); await _cache.lock();
} }
if (boolArg('force')) { if (boolArg('force')) {
_cache.clearStampFiles(); _cache.clearStampFiles();

View File

@ -120,6 +120,7 @@ Future<T> runInContext<T>(
fileSystem: globals.fs, fileSystem: globals.fs,
logger: globals.logger, logger: globals.logger,
platform: globals.platform, platform: globals.platform,
osUtils: globals.os,
), ),
CocoaPods: () => CocoaPods( CocoaPods: () => CocoaPods(
fileSystem: globals.fs, fileSystem: globals.fs,

View File

@ -962,7 +962,7 @@ abstract class FlutterCommand extends Command<void> {
void _registerSignalHandlers(String commandPath, DateTime startTime) { void _registerSignalHandlers(String commandPath, DateTime startTime) {
final SignalHandler handler = (io.ProcessSignal s) { final SignalHandler handler = (io.ProcessSignal s) {
Cache.releaseLock(); globals.cache.releaseLock();
_sendPostUsage( _sendPostUsage(
commandPath, commandPath,
const FlutterCommandResult(ExitStatus.killed), const FlutterCommandResult(ExitStatus.killed),
@ -1035,7 +1035,7 @@ abstract class FlutterCommand extends Command<void> {
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(); globals.cache.releaseLock();
await validateCommand(); await validateCommand();

View File

@ -235,7 +235,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.logger.quiet = topLevelResults['quiet'] as bool; globals.logger.quiet = topLevelResults['quiet'] as bool;
if (globals.platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') { if (globals.platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await Cache.lock(); await globals.cache.lock();
} }
if (topLevelResults['suppress-analytics'] as bool) { if (topLevelResults['suppress-analytics'] as bool) {

View File

@ -484,7 +484,7 @@ class FlutterVersion {
/// Returns null if the cached version is out-of-date or missing, and we are /// Returns null if the cached version is out-of-date or missing, and we are
/// unable to reach the server to get the latest version. /// unable to reach the server to get the latest version.
Future<DateTime> _getLatestAvailableFlutterDate() async { Future<DateTime> _getLatestAvailableFlutterDate() async {
Cache.checkLockAcquired(); globals.cache.checkLockAcquired();
final VersionCheckStamp versionCheckStamp = await VersionCheckStamp.load(); final VersionCheckStamp versionCheckStamp = await VersionCheckStamp.load();
if (versionCheckStamp.lastTimeVersionWasChecked != null) { if (versionCheckStamp.lastTimeVersionWasChecked != null) {

View File

@ -20,7 +20,7 @@ void main() {
setUp(() { setUp(() {
cache = MockCache(); cache = MockCache();
// Release lock between test cases. // Release lock between test cases.
Cache.releaseLock(); cache.releaseLock();
when(cache.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false)); when(cache.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false));
when(cache.updateAll(any)).thenAnswer((Invocation invocation) { when(cache.updateAll(any)).thenAnswer((Invocation invocation) {
@ -39,9 +39,8 @@ void main() {
); );
await createTestCommandRunner(command).run(const <String>['precache']); await createTestCommandRunner(command).run(const <String>['precache']);
expect(Cache.isLocked(), isTrue);
// Do not throw StateError, lock is acquired. // Do not throw StateError, lock is acquired.
expect(() => Cache.checkLockAcquired(platform), returnsNormally); expect(() => cache.checkLockAcquired(), returnsNormally);
}); });
testUsingContext('precache should not re-entrantly acquire lock', () async { testUsingContext('precache should not re-entrantly acquire lock', () async {
@ -62,7 +61,7 @@ void main() {
expect(Cache.isLocked(), isFalse); expect(Cache.isLocked(), isFalse);
// Do not throw StateError, acquired reentrantly with FLUTTER_ALREADY_LOCKED. // Do not throw StateError, acquired reentrantly with FLUTTER_ALREADY_LOCKED.
expect(() => Cache.checkLockAcquired(platform), returnsNormally); expect(() => cache.checkLockAcquired(), returnsNormally);
}); });
testUsingContext('precache downloads web artifacts on dev branch when feature is enabled.', () async { testUsingContext('precache downloads web artifacts on dev branch when feature is enabled.', () async {

View File

@ -1024,7 +1024,7 @@ plugin1=${plugin1.path}
when(mockAndroidSdk.directory).thenReturn('irrelevant'); when(mockAndroidSdk.directory).thenReturn('irrelevant');
final Directory rootDirectory = fileSystem.currentDirectory; final Directory rootDirectory = fileSystem.currentDirectory;
cache = Cache( cache = Cache.test(
rootOverride: rootDirectory, rootOverride: rootDirectory,
fileSystem: fileSystem, fileSystem: fileSystem,
); );

View File

@ -72,7 +72,7 @@ void main() {
'zipStorePath=wrapper/dists\n' 'zipStorePath=wrapper/dists\n'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n'); 'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir), Cache: () => Cache.test(rootOverride: tempDir, fileSystem: memoryFileSystem),
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
@ -113,7 +113,7 @@ void main() {
'zipStorePath=wrapper/dists\n' 'zipStorePath=wrapper/dists\n'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n'); 'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir), Cache: () => Cache.test(rootOverride: tempDir, fileSystem: memoryFileSystem),
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });

View File

@ -14,29 +14,16 @@ import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/dart/pub.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
import '../src/testbed.dart';
void main() { void main() {
group('$Cache.checkLockAcquired', () { group('Cache.checkLockAcquired', () {
MockFileSystem mockFileSystem;
MemoryFileSystem memoryFileSystem;
MockFile mockFile;
MockRandomAccessFile mockRandomAccessFile;
setUp(() { setUp(() {
mockFileSystem = MockFileSystem();
memoryFileSystem = MemoryFileSystem.test();
mockFile = MockFile();
mockRandomAccessFile = MockRandomAccessFile();
when(mockFileSystem.path).thenReturn(memoryFileSystem.path);
Cache.enableLocking(); Cache.enableLocking();
}); });
@ -44,145 +31,146 @@ void main() {
// Restore locking to prevent potential side-effects in // Restore locking to prevent potential side-effects in
// tests outside this group (this option is globally shared). // tests outside this group (this option is globally shared).
Cache.enableLocking(); Cache.enableLocking();
Cache.releaseLock();
}); });
test('should throw when locking is not acquired', () { testWithoutContext('should throw when locking is not acquired', () {
expect(Cache.checkLockAcquired, throwsStateError); final Cache cache = Cache.test();
expect(cache.checkLockAcquired, throwsStateError);
}); });
test('should not throw when locking is disabled', () { testWithoutContext('should not throw when locking is disabled', () {
final Cache cache = Cache.test();
Cache.disableLocking(); Cache.disableLocking();
Cache.checkLockAcquired();
expect(cache.checkLockAcquired, returnsNormally);
}); });
testUsingContext('should not throw when lock is acquired', () async { testWithoutContext('should not throw when lock is acquired', () async {
when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile); Cache.flutterRoot = '';
when(mockFile.openSync(mode: anyNamed('mode'))).thenReturn(mockRandomAccessFile); final FileSystem fileSystem = MemoryFileSystem.test();
await Cache.lock(); final Cache cache = Cache.test(fileSystem: fileSystem);
Cache.checkLockAcquired(); fileSystem.file(fileSystem.path.join('bin', 'cache', 'lockfile'))
Cache.releaseLock(); .createSync(recursive: true);
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('throws tool exit when lockfile open fails', () async { await cache.lock();
when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
when(mockFile.openSync(mode: anyNamed('mode'))).thenThrow(const FileSystemException());
expect(() async => await Cache.lock(), throwsToolExit());
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () async { expect(cache.checkLockAcquired, returnsNormally);
Cache.checkLockAcquired(); expect(cache.releaseLock, returnsNormally);
}, overrides: <Type, Generator>{ }, skip: true); // TODO(jonahwilliams): implement support for lock so this can be tested with the memory file system.
Platform: () => FakePlatform()..environment = <String, String>{'FLUTTER_ALREADY_LOCKED': 'true'},
testWithoutContext('throws tool exit when lockfile open fails', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test(fileSystem: fileSystem);
fileSystem.file(fileSystem.path.join('bin', 'cache', 'lockfile'))
.createSync(recursive: true);
expect(() async => await cache.lock(), throwsToolExit());
}, skip: true); // TODO(jonahwilliams): implement support for lock so this can be tested with the memory file system.
testWithoutContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () {
final Cache cache = Cache.test(platform: FakePlatform(environment: <String, String>{
'FLUTTER_ALREADY_LOCKED': 'true',
}));
expect(cache.checkLockAcquired, returnsNormally);
}); });
}); });
group('Cache', () { group('Cache', () {
MockCache mockCache; testWithoutContext('Continues on failed stamp file update', () async {
Cache cache; final FileSystem fileSystem = MemoryFileSystem.test();
MemoryFileSystem memoryFileSystem; final BufferLogger logger = BufferLogger.test();
ProcessManager fakeProcessManager; final Cache mockCache = MockCache();
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
setUp(() {
fakeProcessManager = FakeProcessManager.any();
mockCache = MockCache();
cache = Cache.test(
fileSystem: memoryFileSystem,
processManager: fakeProcessManager,
);
memoryFileSystem = MemoryFileSystem.test();
});
testUsingContext('Continues on failed stamp file update', () async {
final Directory artifactDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
final Directory downloadDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir); when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
when(mockCache.getDownloadDir()).thenReturn(downloadDir); when(mockCache.getDownloadDir()).thenReturn(downloadDir);
when(mockCache.setStampFor(any, any)).thenAnswer((_) { when(mockCache.setStampFor(any, any)).thenAnswer((_) {
throw const FileSystemException('stamp write failed'); throw const FileSystemException('stamp write failed');
}); });
final FakeSimpleArtifact artifact = FakeSimpleArtifact(mockCache); final FakeSimpleArtifact artifact = FakeSimpleArtifact(mockCache);
await artifact.update(MockArtifactUpdater()); await artifact.update(MockArtifactUpdater(), logger, fileSystem, MockOperatingSystemUtils());
expect(testLogger.errorText, contains('stamp write failed'));
}, overrides: <Type, Generator>{ expect(logger.errorText, contains('stamp write failed'));
Cache: () => mockCache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () { testWithoutContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
final GradleWrapper gradleWrapper = GradleWrapper(cache); final GradleWrapper gradleWrapper = GradleWrapper(cache);
final Directory directory = cache.getCacheDir(globals.fs.path.join('artifacts', 'gradle_wrapper')); final Directory directory = cache.getCacheDir(fileSystem.path.join('artifacts', 'gradle_wrapper'));
globals.fs.file(globals.fs.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true); fileSystem.file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
expect(gradleWrapper.isUpToDateInner(), false); expect(gradleWrapper.isUpToDateInner(fileSystem), false);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () { testWithoutContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
final GradleWrapper gradleWrapper = GradleWrapper(cache); final GradleWrapper gradleWrapper = GradleWrapper(cache);
final Directory directory = cache.getCacheDir(globals.fs.path.join('artifacts', 'gradle_wrapper')); final Directory directory = cache.getCacheDir(fileSystem.path.join('artifacts', 'gradle_wrapper'));
globals.fs.file(globals.fs.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true); fileSystem.file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
globals.fs.file(globals.fs.path.join(directory.path, 'gradlew')).createSync(recursive: true); fileSystem.file(fileSystem.path.join(directory.path, 'gradlew')).createSync(recursive: true);
globals.fs.file(globals.fs.path.join(directory.path, 'gradlew.bat')).createSync(recursive: true); fileSystem.file(fileSystem.path.join(directory.path, 'gradlew.bat')).createSync(recursive: true);
expect(gradleWrapper.isUpToDateInner(), true); expect(gradleWrapper.isUpToDateInner(fileSystem), true);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('should not be up to date, if some cached artifact is not', () async { testWithoutContext('should not be up to date, if some cached artifact is not', () async {
final CachedArtifact artifact1 = MockCachedArtifact(); final CachedArtifact artifact1 = MockCachedArtifact();
final CachedArtifact artifact2 = MockCachedArtifact(); final CachedArtifact artifact2 = MockCachedArtifact();
when(artifact1.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(true)); final FileSystem fileSystem = MemoryFileSystem.test();
when(artifact2.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false));
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); when(artifact1.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(true));
when(artifact2.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(false));
final Cache cache = Cache.test(
fileSystem: fileSystem,
artifacts: <CachedArtifact>[artifact1, artifact2],
processManager: FakeProcessManager.any(),
);
expect(await cache.isUpToDate(), isFalse); expect(await cache.isUpToDate(), isFalse);
}, overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => MemoryFileSystem.test(),
}); });
testUsingContext('should be up to date, if all cached artifacts are', () async { testWithoutContext('should be up to date, if all cached artifacts are', () async {
final CachedArtifact artifact1 = MockCachedArtifact(); final CachedArtifact artifact1 = MockCachedArtifact();
final CachedArtifact artifact2 = MockCachedArtifact(); final CachedArtifact artifact2 = MockCachedArtifact();
when(artifact1.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(true)); final FileSystem fileSystem = MemoryFileSystem.test();
when(artifact2.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(true));
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); when(artifact1.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(true));
when(artifact2.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(true));
final Cache cache = Cache.test(
fileSystem: fileSystem,
artifacts: <CachedArtifact>[artifact1, artifact2],
processManager: FakeProcessManager.any(),
);
expect(await cache.isUpToDate(), isTrue); expect(await cache.isUpToDate(), isTrue);
}, overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => MemoryFileSystem.test(),
}); });
testUsingContext('should update cached artifacts which are not up to date', () async { testWithoutContext('should update cached artifacts which are not up to date', () async {
final CachedArtifact artifact1 = MockCachedArtifact(); final CachedArtifact artifact1 = MockCachedArtifact();
final CachedArtifact artifact2 = MockCachedArtifact(); final CachedArtifact artifact2 = MockCachedArtifact();
when(artifact1.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(true)); final FileSystem fileSystem = MemoryFileSystem.test();
when(artifact2.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false));
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); when(artifact1.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(true));
when(artifact2.isUpToDate(fileSystem)).thenAnswer((Invocation _) => Future<bool>.value(false));
final Cache cache = Cache.test(
fileSystem: fileSystem,
artifacts: <CachedArtifact>[artifact1, artifact2],
processManager: FakeProcessManager.any(),
);
await cache.updateAll(<DevelopmentArtifact>{ await cache.updateAll(<DevelopmentArtifact>{
null, null,
}); });
verifyNever(artifact1.update(any)); verifyNever(artifact1.update(any, any, any, any));
verify(artifact2.update(any)); verify(artifact2.update(any, any, any, any));
}, overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => MemoryFileSystem.test(),
}); });
testUsingContext("getter dyLdLibEntry concatenates the output of each artifact's dyLdLibEntry getter", () async { testWithoutContext("getter dyLdLibEntry concatenates the output of each artifact's dyLdLibEntry getter", () async {
final IosUsbArtifacts artifact1 = MockIosUsbArtifacts(); final IosUsbArtifacts artifact1 = MockIosUsbArtifacts();
final IosUsbArtifacts artifact2 = MockIosUsbArtifacts(); final IosUsbArtifacts artifact2 = MockIosUsbArtifacts();
final IosUsbArtifacts artifact3 = MockIosUsbArtifacts(); final IosUsbArtifacts artifact3 = MockIosUsbArtifacts();
@ -198,7 +186,10 @@ void main() {
.thenReturn(<String, String>{ .thenReturn(<String, String>{
'DYLD_LIBRARY_PATH': '', 'DYLD_LIBRARY_PATH': '',
}); });
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2, artifact3]); final Cache cache = Cache.test(
artifacts: <CachedArtifact>[artifact1, artifact2, artifact3],
processManager: FakeProcessManager.any(),
);
expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH'); expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH');
expect( expect(
@ -207,45 +198,47 @@ void main() {
); );
}); });
testUsingContext('failed storage.googleapis.com download shows China warning', () async { testWithoutContext('failed storage.googleapis.com download shows China warning', () async {
final CachedArtifact artifact1 = MockCachedArtifact(); final CachedArtifact artifact1 = MockCachedArtifact();
final CachedArtifact artifact2 = MockCachedArtifact(); final CachedArtifact artifact2 = MockCachedArtifact();
when(artifact1.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false)); when(artifact1.isUpToDate(any)).thenAnswer((Invocation _) => Future<bool>.value(false));
when(artifact2.isUpToDate()).thenAnswer((Invocation _) => Future<bool>.value(false)); when(artifact2.isUpToDate(any)).thenAnswer((Invocation _) => Future<bool>.value(false));
final MockInternetAddress address = MockInternetAddress(); final MockInternetAddress address = MockInternetAddress();
when(address.host).thenReturn('storage.googleapis.com'); when(address.host).thenReturn('storage.googleapis.com');
when(artifact1.update(any)).thenThrow(SocketException( when(artifact1.update(any, any, any, any)).thenThrow(SocketException(
'Connection reset by peer', 'Connection reset by peer',
address: address, address: address,
)); ));
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); final BufferLogger logger = BufferLogger.test();
final Cache cache = Cache.test(
artifacts: <CachedArtifact>[artifact1, artifact2],
processManager: FakeProcessManager.any(),
logger: logger,
);
try { try {
await cache.updateAll(<DevelopmentArtifact>{ await cache.updateAll(<DevelopmentArtifact>{
null, null,
}); });
fail('Mock thrown exception expected'); fail('Mock thrown exception expected');
} on Exception { } on Exception {
verify(artifact1.update(any)); verify(artifact1.update(any, any, any, any));
// Don't continue when retrieval fails. // Don't continue when retrieval fails.
verifyNever(artifact2.update(any)); verifyNever(artifact2.update(any, any, any, any));
expect( expect(
testLogger.errorText, logger.errorText,
contains('https://flutter.dev/community/china'), contains('https://flutter.dev/community/china'),
); );
} }
}, overrides: <Type, Generator>{
ProcessManager: () => FakeProcessManager.any(),
FileSystem: () => MemoryFileSystem.test(),
}); });
testUsingContext('Invalid URI for FLUTTER_STORAGE_BASE_URL throws ToolExit', () async { testWithoutContext('Invalid URI for FLUTTER_STORAGE_BASE_URL throws ToolExit', () async {
final Cache cache = Cache(); final Cache cache = Cache.test(
platform: FakePlatform(environment: <String, String>{
'FLUTTER_STORAGE_BASE_URL': ' http://foo',
},
));
expect(() => cache.storageBaseUrl, throwsToolExit()); expect(() => cache.storageBaseUrl, throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => FakePlatform(environment: <String, String>{
'FLUTTER_STORAGE_BASE_URL': ' http://foo',
}),
}); });
}); });
@ -255,176 +248,96 @@ void main() {
expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev'), MemoryFileSystem.test()), 'www.flutter.dev'); expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev'), MemoryFileSystem.test()), 'www.flutter.dev');
}); });
group('EngineCachedArtifact', () { testWithoutContext('EngineCachedArtifact makes binary dirs readable and executable by all', () async {
FakePlatform fakePlatform; final OperatingSystemUtils operatingSystemUtils = MockOperatingSystemUtils();
MemoryFileSystem fileSystem; final MockCache cache = MockCache();
MockCache mockCache; final FileSystem fileSystem = MemoryFileSystem.test();
MockOperatingSystemUtils mockOperatingSystemUtils; final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
setUp(() { when(cache.getArtifactDirectory(any)).thenReturn(artifactDir);
fakePlatform = FakePlatform(environment: const <String, String>{}, operatingSystem: 'linux'); when(cache.getDownloadDir()).thenReturn(downloadDir);
mockCache = MockCache(); artifactDir.childDirectory('bin_dir').createSync();
mockOperatingSystemUtils = MockOperatingSystemUtils(); artifactDir.childFile('unused_url_path').createSync();
fileSystem = MemoryFileSystem.test();
});
testUsingContext('makes binary dirs readable and executable by all', () async { final FakeCachedArtifact artifact = FakeCachedArtifact(
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.'); cache: cache,
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.'); binaryDirs: <List<String>>[
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir); <String>['bin_dir', 'unused_url_path'],
when(mockCache.getDownloadDir()).thenReturn(downloadDir); ],
artifactDir.childDirectory('bin_dir').createSync(); requiredArtifacts: DevelopmentArtifact.universal,
artifactDir.childFile('unused_url_path').createSync(); );
await artifact.updateInner(MockArtifactUpdater(), fileSystem, operatingSystemUtils);
final Directory dir = fileSystem.systemTempDirectory
.listSync(recursive: true)
.whereType<Directory>()
.singleWhere((Directory directory) => directory.basename == 'bin_dir', orElse: () => null);
final FakeCachedArtifact artifact = FakeCachedArtifact( expect(dir, isNotNull);
cache: mockCache, expect(dir.path, artifactDir.childDirectory('bin_dir').path);
binaryDirs: <List<String>>[ verify(operatingSystemUtils.chmod(argThat(hasPath(dir.path)), 'a+r,a+x'));
<String>['bin_dir', 'unused_url_path'],
],
requiredArtifacts: DevelopmentArtifact.universal,
);
await artifact.updateInner(MockArtifactUpdater());
final Directory dir = fileSystem.systemTempDirectory
.listSync(recursive: true)
.whereType<Directory>()
.singleWhere((Directory directory) => directory.basename == 'bin_dir', orElse: () => null);
expect(dir, isNotNull);
expect(dir.path, artifactDir.childDirectory('bin_dir').path);
verify(mockOperatingSystemUtils.chmod(argThat(hasPath(dir.path)), 'a+r,a+x'));
}, overrides: <Type, Generator>{
Cache: () => mockCache,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
OperatingSystemUtils: () => mockOperatingSystemUtils,
Platform: () => fakePlatform,
});
}); });
group('AndroidMavenArtifacts', () { testWithoutContext('IosUsbArtifacts verifies executables for libimobiledevice in isUpToDateInner', () async {
MemoryFileSystem memoryFileSystem; final FileSystem fileSystem = MemoryFileSystem.test();
MockProcessManager processManager; final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
Cache cache; final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', cache, platform: FakePlatform(operatingSystem: 'macos'));
iosUsbArtifacts.location.createSync();
final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot')
..createSync();
iosUsbArtifacts.location.childFile('idevicesyslog')
.createSync();
setUp(() { expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
memoryFileSystem = MemoryFileSystem.test();
processManager = MockProcessManager();
cache = Cache.test(
fileSystem: memoryFileSystem,
processManager: FakeProcessManager.any(),
);
});
test('development artifact', () async { ideviceScreenshotFile.deleteSync();
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache);
expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
});
testUsingContext('update', () async { expect(iosUsbArtifacts.isUpToDateInner(fileSystem), false);
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache);
expect(await mavenArtifacts.isUpToDate(), isFalse);
final Directory gradleWrapperDir = cache.getArtifactDirectory('gradle_wrapper')..createSync(recursive: true);
gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant');
gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant');
when(globals.processManager.run(any, environment: captureAnyNamed('environment')))
.thenAnswer((Invocation invocation) {
final List<String> args = invocation.positionalArguments[0] as List<String>;
expect(args.length, 6);
expect(args[1], '-b');
expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
expect(args[5], 'resolveDependencies');
expect(invocation.namedArguments[#environment], gradleEnvironment);
return Future<ProcessResult>.value(ProcessResult(0, 0, '', ''));
});
await mavenArtifacts.update(MockArtifactUpdater());
expect(await mavenArtifacts.isUpToDate(), isFalse);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => processManager,
});
}); });
group('macOS artifacts', () { testWithoutContext('IosUsbArtifacts verifies iproxy for usbmuxd in isUpToDateInner', () async {
Cache cache; final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('usbmuxd', cache, platform: FakePlatform(operatingSystem: 'macos'));
iosUsbArtifacts.location.createSync();
final File iproxy = iosUsbArtifacts.location.childFile('iproxy')
..createSync();
setUp(() { expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
cache = Cache.test(
processManager: FakeProcessManager.any(),
);
});
testUsingContext('verifies executables for libimobiledevice in isUpToDateInner', () async { iproxy.deleteSync();
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', cache);
iosUsbArtifacts.location.createSync();
final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot')
..createSync();
iosUsbArtifacts.location.childFile('idevicesyslog')
.createSync();
expect(iosUsbArtifacts.isUpToDateInner(), true); expect(iosUsbArtifacts.isUpToDateInner(fileSystem), false);
ideviceScreenshotFile.deleteSync();
expect(iosUsbArtifacts.isUpToDateInner(), false);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('verifies iproxy for usbmuxd in isUpToDateInner', () async {
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('usbmuxd', cache);
iosUsbArtifacts.location.createSync();
final File iproxy = iosUsbArtifacts.location.childFile('iproxy')
..createSync();
expect(iosUsbArtifacts.isUpToDateInner(), true);
iproxy.deleteSync();
expect(iosUsbArtifacts.isUpToDateInner(), false);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Does not verify executables for openssl in isUpToDateInner', () async {
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('openssl', cache);
iosUsbArtifacts.location.createSync();
expect(iosUsbArtifacts.isUpToDateInner(), true);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('use unsigned when specified', () async {
cache.useUnsignedMacBinaries = true;
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache);
expect(iosUsbArtifacts.archiveUri.toString(), contains('/unsigned/'));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('not use unsigned when not specified', () async {
cache.useUnsignedMacBinaries = false;
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache);
expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/')));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
}); });
testWithoutContext('Downloads Flutter runner debug symbols', () async { testWithoutContext('IosUsbArtifacts does not verify executables for openssl in isUpToDateInner', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('openssl', cache, platform: FakePlatform(operatingSystem: 'macos'));
iosUsbArtifacts.location.createSync();
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
});
testWithoutContext('IosUsbArtifacts uses unsigned when specified', () async {
final Cache cache = Cache.test();
cache.useUnsignedMacBinaries = true;
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache, platform: FakePlatform(operatingSystem: 'macos'));
expect(iosUsbArtifacts.archiveUri.toString(), contains('/unsigned/'));
});
testWithoutContext('IosUsbArtifacts does not use unsigned when not specified', () async {
final Cache cache = Cache.test();
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache, platform: FakePlatform(operatingSystem: 'macos'));
expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/')));
});
testWithoutContext('FlutterRunnerDebugSymbols downloads Flutter runner debug symbols', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final Cache cache = Cache.test( final Cache cache = Cache.test(
fileSystem: fileSystem,
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
); );
final MockVersionedPackageResolver mockPackageResolver = MockVersionedPackageResolver(); final MockVersionedPackageResolver mockPackageResolver = MockVersionedPackageResolver();
@ -435,7 +348,7 @@ void main() {
); );
when(mockPackageResolver.resolveUrl(any, any)).thenReturn(''); when(mockPackageResolver.resolveUrl(any, any)).thenReturn('');
await flutterRunnerDebugSymbols.updateInner(MockArtifactUpdater()); await flutterRunnerDebugSymbols.updateInner(MockArtifactUpdater(), fileSystem, MockOperatingSystemUtils());
verifyInOrder(<void>[ verifyInOrder(<void>[
mockPackageResolver.resolveUrl('fuchsia-debug-symbols-x64', any), mockPackageResolver.resolveUrl('fuchsia-debug-symbols-x64', any),
@ -443,70 +356,64 @@ void main() {
]); ]);
}); });
testUsingContext('FontSubset in univeral artifacts', () { testWithoutContext('FontSubset in universal artifacts', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
expect(artifacts.developmentArtifact, DevelopmentArtifact.universal); expect(artifacts.developmentArtifact, DevelopmentArtifact.universal);
}); });
testUsingContext('FontSubset artifacts on linux', () { testWithoutContext('FontSubset artifacts on linux', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]); expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]);
}, overrides: <Type, Generator> {
Platform: () => FakePlatform(operatingSystem: 'linux'),
}); });
testUsingContext('FontSubset artifacts on windows', () { testWithoutContext('FontSubset artifacts on windows', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'windows'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['windows-x64', 'windows-x64/font-subset.zip']]); expect(artifacts.getBinaryDirs(), <List<String>>[<String>['windows-x64', 'windows-x64/font-subset.zip']]);
}, overrides: <Type, Generator> {
Platform: () => FakePlatform(operatingSystem: 'windows'),
}); });
testUsingContext('FontSubset artifacts on macos', () { testWithoutContext('FontSubset artifacts on macos', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'macos'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['darwin-x64', 'darwin-x64/font-subset.zip']]); expect(artifacts.getBinaryDirs(), <List<String>>[<String>['darwin-x64', 'darwin-x64/font-subset.zip']]);
}, overrides: <Type, Generator> {
Platform: () => FakePlatform(operatingSystem: 'macos'),
}); });
testUsingContext('FontSubset artifacts on fuchsia', () { testWithoutContext('FontSubset artifacts on fuchsia', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
expect(artifacts.getBinaryDirs, throwsToolExit(message: 'Unsupported operating system: ${globals.platform.operatingSystem}'));
}, overrides: <Type, Generator> { expect(artifacts.getBinaryDirs, throwsToolExit(message: 'Unsupported operating system: fuchsia'));
Platform: () => FakePlatform(operatingSystem: 'fuchsia'),
}); });
testUsingContext('FontSubset artifacts for all platforms', () { testWithoutContext('FontSubset artifacts for all platforms', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache); final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
cache.includeAllPlatforms = true; cache.includeAllPlatforms = true;
expect(artifacts.getBinaryDirs(), <List<String>>[ expect(artifacts.getBinaryDirs(), <List<String>>[
<String>['darwin-x64', 'darwin-x64/font-subset.zip'], <String>['darwin-x64', 'darwin-x64/font-subset.zip'],
<String>['linux-x64', 'linux-x64/font-subset.zip'], <String>['linux-x64', 'linux-x64/font-subset.zip'],
<String>['windows-x64', 'windows-x64/font-subset.zip'], <String>['windows-x64', 'windows-x64/font-subset.zip'],
]); ]);
}, overrides: <Type, Generator> {
Platform: () => FakePlatform(operatingSystem: 'fuchsia'),
}); });
testUsingContext('macOS desktop artifacts ignore filtering when requested', () { testWithoutContext('macOS desktop artifacts ignore filtering when requested', () {
final Cache cache = Cache.test(); final Cache cache = Cache.test();
final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache); final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
cache.includeAllPlatforms = false; cache.includeAllPlatforms = false;
cache.platformOverrideArtifacts = <String>{'macos'}; cache.platformOverrideArtifacts = <String>{'macos'};
expect(artifacts.getBinaryDirs(), isNotEmpty); expect(artifacts.getBinaryDirs(), isNotEmpty);
}, overrides: <Type, Generator> {
Platform: () => FakePlatform(operatingSystem: 'linux'),
}); });
testWithoutContext('Windows desktop artifacts ignore filtering when requested', () { testWithoutContext('Windows desktop artifacts ignore filtering when requested', () {
@ -652,7 +559,7 @@ void main() {
}); });
webStuff.childFile('bar').createSync(recursive: true); webStuff.childFile('bar').createSync(recursive: true);
webSdk.updateInner(artifactUpdater); webSdk.updateInner(artifactUpdater, fileSystem, MockOperatingSystemUtils());
expect(webStuff.childFile('foo'), exists); expect(webStuff.childFile('foo'), exists);
expect(webStuff.childFile('bar'), isNot(exists)); expect(webStuff.childFile('bar'), isNot(exists));
@ -690,12 +597,11 @@ void main() {
final MemoryFileSystem fileSystem = MemoryFileSystem.test(); final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final PubDependencies pubDependencies = PubDependencies( final PubDependencies pubDependencies = PubDependencies(
flutterRoot: () => '', flutterRoot: () => '',
fileSystem: fileSystem,
logger: logger, logger: logger,
pub: () => MockPub(), pub: () => MockPub(),
); );
expect(await pubDependencies.isUpToDate(), false); // no package config expect(await pubDependencies.isUpToDate(fileSystem), false); // no package config
fileSystem.file('packages/flutter_tools/.packages') fileSystem.file('packages/flutter_tools/.packages')
..createSync(recursive: true) ..createSync(recursive: true)
@ -719,12 +625,12 @@ void main() {
} }
'''); ''');
expect(await pubDependencies.isUpToDate(), false); // dependencies are missing. expect(await pubDependencies.isUpToDate(fileSystem), false); // dependencies are missing.
fileSystem.file('.pub-cache/hosted/pub.dartlang.org/example-7.0.0/lib/foo.dart') fileSystem.file('.pub-cache/hosted/pub.dartlang.org/example-7.0.0/lib/foo.dart')
.createSync(recursive: true); .createSync(recursive: true);
expect(await pubDependencies.isUpToDate(), true); expect(await pubDependencies.isUpToDate(fileSystem), true);
}); });
testWithoutContext('PubDependencies updates via pub get', () async { testWithoutContext('PubDependencies updates via pub get', () async {
@ -733,18 +639,65 @@ void main() {
final MockPub pub = MockPub(); final MockPub pub = MockPub();
final PubDependencies pubDependencies = PubDependencies( final PubDependencies pubDependencies = PubDependencies(
flutterRoot: () => '', flutterRoot: () => '',
fileSystem: fileSystem,
logger: logger, logger: logger,
pub: () => pub, pub: () => pub,
); );
await pubDependencies.update(MockArtifactUpdater()); await pubDependencies.update(MockArtifactUpdater(), logger, fileSystem, MockOperatingSystemUtils());
verify(pub.get( verify(pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: 'packages/flutter_tools', directory: 'packages/flutter_tools',
)).called(1); )).called(1);
}); });
group('AndroidMavenArtifacts', () {
MemoryFileSystem memoryFileSystem;
MockProcessManager processManager;
Cache cache;
setUp(() {
memoryFileSystem = MemoryFileSystem.test();
processManager = MockProcessManager();
cache = Cache.test(
fileSystem: memoryFileSystem,
processManager: FakeProcessManager.any(),
);
});
testWithoutContext('development artifact', () async {
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
});
testUsingContext('update', () async {
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache, platform: FakePlatform(operatingSystem: 'linux'));
expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse);
final Directory gradleWrapperDir = cache.getArtifactDirectory('gradle_wrapper')..createSync(recursive: true);
gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant');
gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant');
when(processManager.run(any, environment: captureAnyNamed('environment')))
.thenAnswer((Invocation invocation) {
final List<String> args = invocation.positionalArguments[0] as List<String>;
expect(args.length, 6);
expect(args[1], '-b');
expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
expect(args[5], 'resolveDependencies');
expect(invocation.namedArguments[#environment], gradleEnvironment);
return Future<ProcessResult>.value(ProcessResult(0, 0, '', ''));
});
await mavenArtifacts.update(MockArtifactUpdater(), BufferLogger.test(), memoryFileSystem, MockOperatingSystemUtils());
expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse);
}, overrides: <Type, Generator>{
Cache: () => cache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => processManager,
});
});
} }
class FakeCachedArtifact extends EngineCachedArtifact { class FakeCachedArtifact extends EngineCachedArtifact {
@ -779,9 +732,7 @@ class FakeSimpleArtifact extends CachedArtifact {
); );
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async { Future<void> updateInner(ArtifactUpdater artifactUpdater, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async { }
// nop.
}
} }
class FakeDownloadedArtifact extends CachedArtifact { class FakeDownloadedArtifact extends CachedArtifact {
@ -794,7 +745,7 @@ class FakeDownloadedArtifact extends CachedArtifact {
final File downloadedFile; final File downloadedFile;
@override @override
Future<void> updateInner(ArtifactUpdater artifactUpdater) async {} Future<void> updateInner(ArtifactUpdater artifactUpdater, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async { }
} }
class MockArtifactUpdater extends Mock implements ArtifactUpdater {} class MockArtifactUpdater extends Mock implements ArtifactUpdater {}

View File

@ -771,7 +771,12 @@ void _testInMemory(String description, Future<void> testMethod()) {
testFileSystem.file('.packages').writeAsStringSync('\n'); testFileSystem.file('.packages').writeAsStringSync('\n');
// Transfer needed parts of the Flutter installation folder // Transfer needed parts of the Flutter installation folder
// to the in-memory file system used during testing. // to the in-memory file system used during testing.
transfer(Cache().getArtifactDirectory('gradle_wrapper'), testFileSystem); transfer(Cache(
fileSystem: globals.fs,
logger: globals.logger,
osUtils: globals.os,
platform: globals.platform,
).getArtifactDirectory('gradle_wrapper'), testFileSystem);
transfer(globals.fs.directory(Cache.flutterRoot) transfer(globals.fs.directory(Cache.flutterRoot)
.childDirectory('packages') .childDirectory('packages')
.childDirectory('flutter_tools') .childDirectory('flutter_tools')
@ -801,7 +806,12 @@ void _testInMemory(String description, Future<void> testMethod()) {
overrides: <Type, Generator>{ overrides: <Type, Generator>{
FileSystem: () => testFileSystem, FileSystem: () => testFileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
Cache: () => Cache(), Cache: () => Cache(
logger: globals.logger,
fileSystem: globals.fs,
osUtils: globals.os,
platform: globals.platform,
),
FlutterProjectFactory: () => flutterProjectFactory, FlutterProjectFactory: () => flutterProjectFactory,
}, },
); );

View File

@ -57,7 +57,7 @@ void main() {
testUsingContext('honors shouldUpdateCache false', () async { testUsingContext('honors shouldUpdateCache false', () async {
final DummyFlutterCommand flutterCommand = DummyFlutterCommand(shouldUpdateCache: false); final DummyFlutterCommand flutterCommand = DummyFlutterCommand(shouldUpdateCache: false);
await flutterCommand.run(); await flutterCommand.run();
verifyZeroInteractions(cache); verifyNever(cache.updateAll(any));
expect(flutterCommand.deprecated, isFalse); expect(flutterCommand.deprecated, isFalse);
expect(flutterCommand.hidden, isFalse); expect(flutterCommand.hidden, isFalse);
}, },
@ -352,7 +352,7 @@ void main() {
final Completer<void> checkLockCompleter = Completer<void>(); final Completer<void> checkLockCompleter = Completer<void>();
final DummyFlutterCommand flutterCommand = final DummyFlutterCommand flutterCommand =
DummyFlutterCommand(commandFunction: () async { DummyFlutterCommand(commandFunction: () async {
await Cache.lock(); await globals.cache.lock();
checkLockCompleter.complete(); checkLockCompleter.complete();
final Completer<void> c = Completer<void>(); final Completer<void> c = Completer<void>();
await c.future; await c.future;
@ -362,13 +362,13 @@ void main() {
unawaited(flutterCommand.run()); unawaited(flutterCommand.run());
await checkLockCompleter.future; await checkLockCompleter.future;
Cache.checkLockAcquired(); globals.cache.checkLockAcquired();
signalController.add(mockSignal); signalController.add(mockSignal);
await completer.future; await completer.future;
await Cache.lock(); await globals.cache.lock();
Cache.releaseLock(); globals.cache.releaseLock();
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessInfo: () => mockProcessInfo, ProcessInfo: () => mockProcessInfo,
Signals: () => FakeSignals( Signals: () => FakeSignals(

View File

@ -4,6 +4,9 @@
import 'dart:async'; import 'dart:async';
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';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
@ -51,12 +54,12 @@ class FakeDyldEnvironmentArtifact extends ArtifactSet {
}; };
@override @override
Future<bool> isUpToDate() => Future<bool>.value(true); Future<bool> isUpToDate(FileSystem fileSystem) => Future<bool>.value(true);
@override @override
String get name => 'fake'; String get name => 'fake';
@override @override
Future<void> update(ArtifactUpdater artifactUpdater) async { Future<void> update(ArtifactUpdater artifactUpdater, Logger logger, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async {
} }
} }

View File

@ -897,5 +897,14 @@ class FakeCache implements Cache {
} }
@override @override
void clearStampFiles() {} void clearStampFiles() { }
@override
void checkLockAcquired() { }
@override
Future<void> lock() async { }
@override
void releaseLock() { }
} }