diff --git a/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart b/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart index a38081fe0..b3eb437a2 100644 --- a/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart +++ b/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:isolate'; import 'package:archive/archive_io.dart'; import 'package:collection/collection.dart'; @@ -74,20 +75,27 @@ abstract class ArchiveDiffer { /// Files that have been added, removed, or that have changed between the /// archives at the two provided paths. - FileSetDiff changedFiles(String oldArchivePath, String newArchivePath) => - FileSetDiff.fromPathHashes( - oldPathHashes: fileHashes(File(oldArchivePath)), - newPathHashes: fileHashes(File(newArchivePath)), - ); + Future changedFiles( + String oldArchivePath, + String newArchivePath, + ) async { + return FileSetDiff.fromPathHashes( + oldPathHashes: await fileHashes(File(oldArchivePath)), + newPathHashes: await fileHashes(File(newArchivePath)), + ); + } + + Future fileHashes(File archive) async { + return Isolate.run(() { + final zipDirectory = ZipDirectory.read(InputFileStream(archive.path)); - PathHashes fileHashes(File archive) { - final zipDirectory = ZipDirectory.read(InputFileStream(archive.path)); - return { - for (final file in zipDirectory.fileHeaders) - // Zip files contain an (optional) crc32 checksum for a file. IPAs and - // AARs seem to always include this for files, so a quick way for us to - // tell if file contents differ is if their checksums differ. - file.filename: file.crc32!.toString(), - }; + return { + for (final file in zipDirectory.fileHeaders) + // Zip files contain an (optional) crc32 checksum for a file. IPAs and + // AARs seem to always include this for files, so a quick way for us + // to tell if file contents differ is if their checksums differ. + file.filename: file.crc32!.toString(), + }; + }); } } diff --git a/packages/shorebird_cli/lib/src/archive_analysis/ios_archive_differ.dart b/packages/shorebird_cli/lib/src/archive_analysis/ios_archive_differ.dart index ec4e310b3..b0bbf3352 100644 --- a/packages/shorebird_cli/lib/src/archive_analysis/ios_archive_differ.dart +++ b/packages/shorebird_cli/lib/src/archive_analysis/ios_archive_differ.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:isolate'; import 'package:archive/archive_io.dart'; import 'package:collection/collection.dart'; @@ -32,15 +33,18 @@ class IosArchiveDiffer extends ArchiveDiffer { /// archives at the two provided paths. This method will also unisgn mach-o /// binaries in the archives before computing the diff. @override - FileSetDiff changedFiles(String oldArchivePath, String newArchivePath) { - final oldPathHashes = fileHashes(File(oldArchivePath)); - final newPathHashes = fileHashes(File(newArchivePath)); - - _updateHashes( + Future changedFiles( + String oldArchivePath, + String newArchivePath, + ) async { + var oldPathHashes = await fileHashes(File(oldArchivePath)); + var newPathHashes = await fileHashes(File(newArchivePath)); + + oldPathHashes = await _updateHashes( archivePath: oldArchivePath, pathHashes: oldPathHashes, ); - _updateHashes( + newPathHashes = await _updateHashes( archivePath: newArchivePath, pathHashes: newPathHashes, ); @@ -55,17 +59,21 @@ class IosArchiveDiffer extends ArchiveDiffer { /// includes: /// - Signed files (those with a .app extension) /// - Compiled asset catalogs (those with a .car extension) - void _updateHashes({ + Future _updateHashes({ required String archivePath, required PathHashes pathHashes, - }) { - for (final file in _filesToUnsign(archivePath)) { - pathHashes[file.name] = _unsignedFileHash(file); - } - - for (final file in _carFiles(archivePath)) { - pathHashes[file.name] = _carFileHash(file); - } + }) async { + return Isolate.run(() async { + for (final file in _filesToUnsign(archivePath)) { + pathHashes[file.name] = await _unsignedFileHash(file); + } + + for (final file in _carFiles(archivePath)) { + pathHashes[file.name] = await _carFileHash(file); + } + + return pathHashes; + }); } List _filesToUnsign(String archivePath) { @@ -90,12 +98,12 @@ class IosArchiveDiffer extends ArchiveDiffer { .toList(); } - String _unsignedFileHash(ArchiveFile file) { + Future _unsignedFileHash(ArchiveFile file) async { final tempDir = Directory.systemTemp.createTempSync(); final outPath = p.join(tempDir.path, file.name); final outputStream = OutputFileStream(outPath); file.writeContent(outputStream); - outputStream.close(); + await outputStream.close(); if (Platform.isMacOS) { // coverage:ignore-start @@ -110,12 +118,12 @@ class IosArchiveDiffer extends ArchiveDiffer { /// Uses assetutil to write a json description of a .car file to disk and /// diffs the contents of that file, less a timestamp line that chnages based /// on when the .car file was created. - String _carFileHash(ArchiveFile file) { + Future _carFileHash(ArchiveFile file) async { final tempDir = Directory.systemTemp.createTempSync(); final outPath = p.join(tempDir.path, file.name); final outputStream = OutputFileStream(outPath); file.writeContent(outputStream); - outputStream.close(); + await outputStream.close(); final assetInfoPath = '$outPath.json'; diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart index bfebf92dd..54d3b1c0e 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart @@ -231,14 +231,17 @@ Current Flutter Revision: $originalFlutterRevision } } + final releaseAabArtifactFile = await artifactManager.downloadFile( + Uri.parse(releaseAabArtifact.url), + ); + downloadReleaseArtifactProgress.complete(); try { - await patchDiffChecker.confirmUnpatchableDiffsIfNecessary( + final diffChecker = patchDiffChecker; + await diffChecker.confirmUnpatchableDiffsIfNecessary( localArtifact: File(bundlePath), - releaseArtifact: await artifactManager.downloadFile( - Uri.parse(releaseAabArtifact.url), - ), + releaseArtifact: releaseAabArtifactFile, archiveDiffer: _archiveDiffer, force: force, ); diff --git a/packages/shorebird_cli/lib/src/patch_diff_checker.dart b/packages/shorebird_cli/lib/src/patch_diff_checker.dart index 6bfda41a1..377029a77 100644 --- a/packages/shorebird_cli/lib/src/patch_diff_checker.dart +++ b/packages/shorebird_cli/lib/src/patch_diff_checker.dart @@ -55,7 +55,7 @@ class PatchDiffChecker { final progress = logger.progress('Verifying patch can be applied to release'); - final contentDiffs = archiveDiffer.changedFiles( + final contentDiffs = await archiveDiffer.changedFiles( releaseArtifact.path, localArtifact.path, ); diff --git a/packages/shorebird_cli/test/src/archive_analysis/android_archive_differ_test.dart b/packages/shorebird_cli/test/src/archive_analysis/android_archive_differ_test.dart index 77aeeb6eb..a472586fb 100644 --- a/packages/shorebird_cli/test/src/archive_analysis/android_archive_differ_test.dart +++ b/packages/shorebird_cli/test/src/archive_analysis/android_archive_differ_test.dart @@ -31,13 +31,15 @@ void main() { group('aab', () { group('changedFiles', () { - test('finds no differences between the same aab', () { - expect(differ.changedFiles(baseAabPath, baseAabPath), isEmpty); + test('finds no differences between the same aab', () async { + expect(await differ.changedFiles(baseAabPath, baseAabPath), isEmpty); }); - test('finds differences between two different aabs', () { + test('finds differences between two different aabs', () async { + final fileSetDiff = + await differ.changedFiles(baseAabPath, changedDartAabPath); expect( - differ.changedFiles(baseAabPath, changedDartAabPath).changedPaths, + fileSetDiff.changedPaths, { 'BUNDLE-METADATA/com.android.tools.build.libraries/dependencies.pb', 'base/lib/arm64-v8a/libapp.so', @@ -52,37 +54,39 @@ void main() { }); group('contentDifferences', () { - test('detects no differences between the same aab', () { - expect(differ.changedFiles(baseAabPath, baseAabPath), isEmpty); + test('detects no differences between the same aab', () async { + expect(await differ.changedFiles(baseAabPath, baseAabPath), isEmpty); }); - test('detects asset changes', () { + test('detects asset changes', () async { final fileSetDiff = - differ.changedFiles(baseAabPath, changedAssetAabPath); + await differ.changedFiles(baseAabPath, changedAssetAabPath); expect(differ.assetsFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects kotlin changes', () { + test('detects kotlin changes', () async { final fileSetDiff = - differ.changedFiles(baseAabPath, changedKotlinAabPath); + await differ.changedFiles(baseAabPath, changedKotlinAabPath); expect(differ.assetsFileSetDiff(fileSetDiff), isEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isNotEmpty); }); - test('detects dart changes', () { + test('detects dart changes', () async { final fileSetDiff = - differ.changedFiles(baseAabPath, changedDartAabPath); + await differ.changedFiles(baseAabPath, changedDartAabPath); expect(differ.assetsFileSetDiff(fileSetDiff), isEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects dart and asset changes', () { - final fileSetDiff = - differ.changedFiles(baseAabPath, changedDartAndAssetAabPath); + test('detects dart and asset changes', () async { + final fileSetDiff = await differ.changedFiles( + baseAabPath, + changedDartAndAssetAabPath, + ); expect(differ.assetsFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); @@ -92,42 +96,43 @@ void main() { group('aar', () { group('changedFiles', () { - test('finds no differences between the same aar', () { - expect(differ.changedFiles(baseAarPath, baseAarPath), isEmpty); + test('finds no differences between the same aar', () async { + expect(await differ.changedFiles(baseAarPath, baseAarPath), isEmpty); }); - test('finds differences between two different aars', () { - expect( - differ.changedFiles(baseAarPath, changedDartAarPath).changedPaths, - {'jni/arm64-v8a/libapp.so'}, - ); + test('finds differences between two different aars', () async { + final fileSetDiff = + await differ.changedFiles(baseAarPath, changedDartAarPath); + expect(fileSetDiff.changedPaths, {'jni/arm64-v8a/libapp.so'}); }); }); group('changedFiles', () { - test('detects no differences between the same aar', () { - expect(differ.changedFiles(baseAarPath, baseAarPath), isEmpty); + test('detects no differences between the same aar', () async { + expect(await differ.changedFiles(baseAarPath, baseAarPath), isEmpty); }); - test('detects asset changes', () { + test('detects asset changes', () async { final fileSetDiff = - differ.changedFiles(baseAarPath, changedAssetAarPath); + await differ.changedFiles(baseAarPath, changedAssetAarPath); expect(differ.assetsFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects dart changes', () { + test('detects dart changes', () async { final fileSetDiff = - differ.changedFiles(baseAarPath, changedDartAarPath); + await differ.changedFiles(baseAarPath, changedDartAarPath); expect(differ.assetsFileSetDiff(fileSetDiff), isEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects dart and asset changes', () { - final fileSetDiff = - differ.changedFiles(baseAarPath, changedDartAndAssetAarPath); + test('detects dart and asset changes', () async { + final fileSetDiff = await differ.changedFiles( + baseAarPath, + changedDartAndAssetAarPath, + ); expect(differ.assetsFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); diff --git a/packages/shorebird_cli/test/src/archive_analysis/archive_differ_test.dart b/packages/shorebird_cli/test/src/archive_analysis/archive_differ_test.dart index 4cf253404..be1867fbb 100644 --- a/packages/shorebird_cli/test/src/archive_analysis/archive_differ_test.dart +++ b/packages/shorebird_cli/test/src/archive_analysis/archive_differ_test.dart @@ -62,7 +62,10 @@ class TestArchiveDiffer extends ArchiveDiffer { FileSetDiff changedFileSetDiff = FileSetDiff.empty(); @override - FileSetDiff changedFiles(String oldArchivePath, String newArchivePath) => + Future changedFiles( + String oldArchivePath, + String newArchivePath, + ) async => changedFileSetDiff; @override diff --git a/packages/shorebird_cli/test/src/archive_analysis/ios_archive_differ_test.dart b/packages/shorebird_cli/test/src/archive_analysis/ios_archive_differ_test.dart index d8889b511..af19cc8b0 100644 --- a/packages/shorebird_cli/test/src/archive_analysis/ios_archive_differ_test.dart +++ b/packages/shorebird_cli/test/src/archive_analysis/ios_archive_differ_test.dart @@ -65,15 +65,15 @@ void main() { group('xcarchive', () { group('changedPaths', () { - test('finds no differences between the same xcarchive', () { + test('finds no differences between the same xcarchive', () async { expect( - differ.changedFiles(baseIpaPath, baseIpaPath), + await differ.changedFiles(baseIpaPath, baseIpaPath), isEmpty, ); }); - test('finds differences between two different xcarchives', () { - final fileSetDiff = differ.changedFiles( + test('finds differences between two different xcarchives', () async { + final fileSetDiff = await differ.changedFiles( baseIpaPath, changedAssetIpaPath, ); @@ -101,9 +101,9 @@ void main() { }); group('changedFiles', () { - test('detects asset changes', () { + test('detects asset changes', () async { final fileSetDiff = - differ.changedFiles(baseIpaPath, changedAssetIpaPath); + await differ.changedFiles(baseIpaPath, changedAssetIpaPath); expect(differ.assetsFileSetDiff(fileSetDiff), isNotEmpty); expect( differ.dartFileSetDiff(fileSetDiff), @@ -112,17 +112,17 @@ void main() { expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects dart changes', () { + test('detects dart changes', () async { final fileSetDiff = - differ.changedFiles(baseIpaPath, changedDartIpaPath); + await differ.changedFiles(baseIpaPath, changedDartIpaPath); expect(differ.assetsFileSetDiff(fileSetDiff), isEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isNotEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects swift changes', () { + test('detects swift changes', () async { final fileSetDiff = - differ.changedFiles(baseIpaPath, changedSwiftIpaPath); + await differ.changedFiles(baseIpaPath, changedSwiftIpaPath); expect(differ.assetsFileSetDiff(fileSetDiff), isEmpty); expect(differ.dartFileSetDiff(fileSetDiff), isEmpty); expect(differ.nativeFileSetDiff(fileSetDiff), isNotEmpty); @@ -130,8 +130,9 @@ void main() { }); group('containsPotentiallyBreakingAssetDiffs', () { - test('returns true if a file in flutter_assets has changed', () { - final fileSetDiff = differ.changedFiles( + test('returns true if a file in flutter_assets has changed', + () async { + final fileSetDiff = await differ.changedFiles( baseIpaPath, changedAssetIpaPath, ); @@ -141,8 +142,9 @@ void main() { ); }); - test('returns false if no files in flutter_assets has changed', () { - final fileSetDiff = differ.changedFiles( + test('returns false if no files in flutter_assets has changed', + () async { + final fileSetDiff = await differ.changedFiles( baseIpaPath, changedDartIpaPath, ); @@ -154,8 +156,8 @@ void main() { }); group('containsPotentiallyBreakingNativeDiffs', () { - test('returns true if Swift files have been changed', () { - final fileSetDiff = differ.changedFiles( + test('returns true if Swift files have been changed', () async { + final fileSetDiff = await differ.changedFiles( baseIpaPath, changedSwiftIpaPath, ); @@ -165,8 +167,8 @@ void main() { ); }); - test('returns false if Swift files have not been changed', () { - final fileSetDiff = differ.changedFiles( + test('returns false if Swift files have not been changed', () async { + final fileSetDiff = await differ.changedFiles( baseIpaPath, changedAssetIpaPath, ); @@ -180,16 +182,20 @@ void main() { group('xcframework', () { group('changedPaths', () { - test('finds no differences between the same zipped xcframeworks', () { + test('finds no differences between the same zipped xcframeworks', + () async { expect( - differ.changedFiles(baseXcframeworkPath, baseXcframeworkPath), + await differ.changedFiles( + baseXcframeworkPath, + baseXcframeworkPath, + ), isEmpty, ); }); test('finds differences between two differed zipped xcframeworks', - () { - final fileSetDiff = differ.changedFiles( + () async { + final fileSetDiff = await differ.changedFiles( baseXcframeworkPath, changedAssetXcframeworkPath, ); @@ -220,8 +226,8 @@ void main() { }); group('changedFiles', () { - test('detects asset changes', () { - final fileSetDiff = differ.changedFiles( + test('detects asset changes', () async { + final fileSetDiff = await differ.changedFiles( baseXcframeworkPath, changedAssetXcframeworkPath, ); @@ -233,8 +239,8 @@ void main() { expect(differ.nativeFileSetDiff(fileSetDiff), isEmpty); }); - test('detects dart changes', () { - final fileSetDiff = differ.changedFiles( + test('detects dart changes', () async { + final fileSetDiff = await differ.changedFiles( baseXcframeworkPath, changedDartXcframeworkPath, ); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart index 4e176dfce..ea4ed8a6f 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart @@ -237,7 +237,7 @@ void main() { .thenAnswer((_) async => releaseArtifactFile); when( () => archiveDiffer.changedFiles(any(), any()), - ).thenReturn(FileSetDiff.empty()); + ).thenAnswer((_) async => FileSetDiff.empty()); when( () => archiveDiffer.containsPotentiallyBreakingAssetDiffs(any()), ).thenReturn(false); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart index 292212560..ec0e703bd 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart @@ -256,7 +256,7 @@ flutter: .thenAnswer((_) async => releaseArtifactFile); when( () => archiveDiffer.changedFiles(any(), any()), - ).thenReturn(FileSetDiff.empty()); + ).thenAnswer((_) async => FileSetDiff.empty()); when( () => archiveDiffer.assetsFileSetDiff(any()), ).thenReturn(FileSetDiff.empty()); diff --git a/packages/shorebird_cli/test/src/patch_diff_checker_test.dart b/packages/shorebird_cli/test/src/patch_diff_checker_test.dart index ff91a259d..9b1df07e3 100644 --- a/packages/shorebird_cli/test/src/patch_diff_checker_test.dart +++ b/packages/shorebird_cli/test/src/patch_diff_checker_test.dart @@ -59,7 +59,7 @@ void main() { patchDiffChecker = PatchDiffChecker(); when(() => archiveDiffer.changedFiles(any(), any())) - .thenReturn(FileSetDiff.empty()); + .thenAnswer((_) async => FileSetDiff.empty()); when(() => archiveDiffer.assetsFileSetDiff(any())) .thenReturn(assetsFileSetDiff); when(() => archiveDiffer.nativeFileSetDiff(any()))