diff --git a/dev/integration_tests/flutter_gallery/macos/Podfile.lock b/dev/integration_tests/flutter_gallery/macos/Podfile.lock new file mode 100644 index 0000000000..56c822bf9b --- /dev/null +++ b/dev/integration_tests/flutter_gallery/macos/Podfile.lock @@ -0,0 +1,35 @@ +PODS: + - connectivity_macos (0.0.1): + - FlutterMacOS + - Reachability + - FlutterMacOS (1.0.0) + - Reachability (3.2) + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - connectivity_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +SPEC REPOS: + trunk: + - Reachability + +EXTERNAL SOURCES: + connectivity_macos: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos + FlutterMacOS: + :path: Flutter/ephemeral + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + connectivity_macos: 9f30e9d0e67a0bc08a0c563ee82310b51ca6e818 + FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 + Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 + url_launcher_macos: 45af3d61de06997666568a7149c1be98b41c95d4 + +PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c + +COCOAPODS: 1.10.1 diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index 5a78d0bd09..6744c03d0f 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -335,10 +335,18 @@ class CocoaPods { _logger.printStatus(stderr, indent: 4); } } + if (result.exitCode != 0) { invalidatePodInstallOutput(xcodeProject); _diagnosePodInstallFailure(result); throwToolExit('Error running pod install'); + } else if (xcodeProject.podfileLock.existsSync()) { + // Even if the Podfile.lock didn't change, update its modified date to now + // so Podfile.lock is newer than Podfile. + _processManager.runSync( + ['touch', xcodeProject.podfileLock.path], + workingDirectory: _fileSystem.path.dirname(xcodeProject.podfile.path), + ); } } diff --git a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart index 7f83e56071..23e02de231 100644 --- a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart @@ -335,7 +335,7 @@ void main() { xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, ), throwsToolExit(message: 'CocoaPods not installed or not in valid state')); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations); }); @@ -347,7 +347,7 @@ void main() { xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, ), throwsToolExit(message: 'CocoaPods not installed or not in valid state')); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations); }); @@ -385,15 +385,21 @@ void main() { final FlutterProject projectUnderTest = setupProjectUnderTest(); pretendPodIsInstalled(); pretendPodVersionIs('1.10.0'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], ), - ); + FakeCommand( + command: ['touch', 'project/macos/Podfile.lock'], + ), + ]); - fileSystem.file(fileSystem.path.join('project', 'macos', 'Podfile')) + projectUnderTest.macos.podfile ..createSync() ..writeAsStringSync('plugin_pods = parse_KV_file(\'../.flutter-plugins\')'); + projectUnderTest.macos.podfileLock + ..createSync() + ..writeAsStringSync('Existing lock file.'); await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.macos, @@ -411,7 +417,7 @@ void main() { xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, ), throwsToolExit(message: 'Podfile missing')); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('throws, if specs repo is outdated.', () async { @@ -556,20 +562,20 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ..createSync(recursive: true) ..writeAsStringSync('Existing lock file.'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/ios', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + ]); final bool didInstall = await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, dependenciesChanged: false, ); expect(didInstall, isTrue); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('runs iOS pod install, if Manifest.lock is missing', () async { @@ -582,20 +588,23 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by projectUnderTest.ios.podfileLock ..createSync() ..writeAsStringSync('Existing lock file.'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/ios', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + FakeCommand( + command: ['touch', 'project/ios/Podfile.lock'], + ), + ]); final bool didInstall = await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, dependenciesChanged: false, ); expect(didInstall, isTrue); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('runs macOS pod install, if Manifest.lock is missing', () async { @@ -608,20 +617,23 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by projectUnderTest.macos.podfileLock ..createSync() ..writeAsStringSync('Existing lock file.'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/macos', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + FakeCommand( + command: ['touch', 'project/macos/Podfile.lock'], + ), + ]); final bool didInstall = await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.macos, buildMode: BuildMode.debug, dependenciesChanged: false, ); expect(didInstall, isTrue); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async { @@ -637,20 +649,23 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by projectUnderTest.ios.podManifestLock ..createSync(recursive: true) ..writeAsStringSync('Different lock file.'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/ios', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + FakeCommand( + command: ['touch', 'project/ios/Podfile.lock'], + ), + ]); final bool didInstall = await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, dependenciesChanged: false, ); expect(didInstall, isTrue); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('runs pod install, if flutter framework changed', () async { @@ -666,20 +681,23 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by projectUnderTest.ios.podManifestLock ..createSync(recursive: true) ..writeAsStringSync('Existing lock file.'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/ios', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + FakeCommand( + command: ['touch', 'project/ios/Podfile.lock'], + ), + ]); final bool didInstall = await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, dependenciesChanged: true, ); expect(didInstall, isTrue); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async { @@ -698,19 +716,22 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by await Future.delayed(const Duration(milliseconds: 10)); projectUnderTest.ios.podfile .writeAsStringSync('Updated Podfile'); - fakeProcessManager.addCommand( - const FakeCommand( + fakeProcessManager.addCommands(const [ + FakeCommand( command: ['pod', 'install', '--verbose'], workingDirectory: 'project/ios', environment: {'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'}, ), - ); + FakeCommand( + command: ['touch', 'project/ios/Podfile.lock'], + ), + ]); await cocoaPodsUnderTest.processPods( xcodeProject: projectUnderTest.ios, buildMode: BuildMode.debug, dependenciesChanged: false, ); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('skips pod install, if nothing changed', () async { @@ -730,7 +751,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by dependenciesChanged: false, ); expect(didInstall, isFalse); - expect(fakeProcessManager.hasRemainingExpectations, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); }); testUsingContext('a failed pod install deletes Pods/Manifest.lock', () async { diff --git a/packages/flutter_tools/test/integration.shard/macos_content_validation_test.dart b/packages/flutter_tools/test/integration.shard/macos_content_validation_test.dart index 943340dd71..bdf3d98feb 100644 --- a/packages/flutter_tools/test/integration.shard/macos_content_validation_test.dart +++ b/packages/flutter_tools/test/integration.shard/macos_content_validation_test.dart @@ -34,19 +34,31 @@ void main() { 'clean', ], workingDirectory: workingDirectory); - final ProcessResult result = processManager.runSync([ + final File podfile = fileSystem.file(fileSystem.path.join(workingDirectory, 'macos', 'Podfile')); + final File podfileLock = fileSystem.file(fileSystem.path.join(workingDirectory, 'macos', 'Podfile.lock')); + expect(podfile, exists); + expect(podfileLock, exists); + + // Simulate a newer Podfile than Podfile.lock. + podfile.setLastModifiedSync(DateTime.now()); + podfileLock.setLastModifiedSync(DateTime.now().subtract(const Duration(days: 1))); + expect(podfileLock.lastModifiedSync().isBefore(podfile.lastModifiedSync()), isTrue); + + final List buildCommand = [ flutterBin, ...getLocalEngineArguments(), 'build', 'macos', '--$buildModeLower', - ], workingDirectory: workingDirectory); + ]; + final ProcessResult result = processManager.runSync(buildCommand, workingDirectory: workingDirectory); print(result.stdout); print(result.stderr); - expect(result.exitCode, 0); + expect(result.stdout, contains('Running pod install')); + final Directory outputApp = fileSystem.directory(fileSystem.path.join( workingDirectory, 'build', @@ -56,6 +68,7 @@ void main() { buildMode, 'flutter_gallery.app', )); + expect(podfile.lastModifiedSync().isBefore(podfileLock.lastModifiedSync()), isTrue); final Directory outputAppFramework = fileSystem.directory(fileSystem.path.join( @@ -118,6 +131,15 @@ void main() { isFalse, ); + // Build again without cleaning. + final ProcessResult secondBuild = processManager.runSync(buildCommand, workingDirectory: workingDirectory); + + print(secondBuild.stdout); + print(secondBuild.stderr); + expect(secondBuild.exitCode, 0); + + expect(secondBuild.stdout, isNot(contains('Running pod install'))); + processManager.runSync([ flutterBin, ...getLocalEngineArguments(),