diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 3b7f4a1f60..c52fb187c0 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -1103,6 +1103,17 @@ class IosUsbArtifacts extends CachedArtifact { 'libzip', ]; + // For unknown reasons, users are getting into bad states where libimobiledevice is + // downloaded but some executables are missing from the zip. The names here are + // used for additional download checks below, so we can redownload if they are + // missing. + static const Map> _kExecutables = >{ + 'libimobiledevice': [ + 'idevice_id', + 'ideviceinfo', + ], + }; + @override Map get environment { return { @@ -1110,11 +1121,28 @@ class IosUsbArtifacts extends CachedArtifact { }; } + @override + bool isUpToDateInner() { + final List executables =_kExecutables[name]; + if (executables == null) { + return true; + } + for (String executable in executables) { + if (!location.childFile(executable).existsSync()) { + return false; + } + } + return true; + } + @override Future updateInner() { if (!platform.isMacOS && !cache.includeAllPlatforms) { return Future.value(); } + if (location.existsSync()) { + location.deleteSync(recursive: true); + } return _downloadZipArchive('Downloading $name...', archiveUri, location); } diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index f1cf2ded7d..be5e4a947a 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -330,13 +330,45 @@ void main() { }); }); - group('Unsigned mac artifacts', () { + group('macOS artifacts', () { MockCache mockCache; setUp(() { mockCache = MockCache(); }); + testUsingContext('verifies executables for libimobiledevice in isUpToDateInner', () async { + final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', mockCache); + when(mockCache.getArtifactDirectory(any)).thenReturn(fs.currentDirectory); + iosUsbArtifacts.location.createSync(); + final File ideviceIdFile = iosUsbArtifacts.location.childFile('idevice_id') + ..createSync(); + iosUsbArtifacts.location.childFile('ideviceinfo') + ..createSync(); + + expect(iosUsbArtifacts.isUpToDateInner(), true); + + ideviceIdFile.deleteSync(); + + expect(iosUsbArtifacts.isUpToDateInner(), false); + }, overrides: { + Cache: () => mockCache, + FileSystem: () => MemoryFileSystem(), + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('Does not verify executables for openssl in isUpToDateInner', () async { + final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('openssl', mockCache); + when(mockCache.getArtifactDirectory(any)).thenReturn(fs.currentDirectory); + iosUsbArtifacts.location.createSync(); + + expect(iosUsbArtifacts.isUpToDateInner(), true); + }, overrides: { + Cache: () => mockCache, + FileSystem: () => MemoryFileSystem(), + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('use unsigned when specified', () async { when(mockCache.useUnsignedMacBinaries).thenReturn(true);