Filter out SwiftPM schemes when fetching schemes#186006
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements a filtering mechanism for Xcode schemes to skip Swift Package Manager schemes, reducing the time spent probing for watchOS companion targets. It verifies the existence of an .xcscheme file in the host project's shared schemes directory. Tests were updated to reflect this requirement and a new test case was added. Feedback indicates that the current implementation may skip valid schemes in workspaces or those not marked as shared.
|
@lukemmtt Do you think this is something you have bandwidth for sometime this week or next? If not, I'll have my team take over so we can get this fixed ASAP. Let me know :) |
|
Thanks for the note! Yes, I'll take a stab at it today and let you know :) |
In iOS projects with a watchOS companion target and Swift Package Manager enabled, IosProject.containsWatchCompanion()'s fallback path iterates every entry in projectInfo.schemes and runs xcodebuild -showBuildSettings -destination generic/platform=watchOS for each one. With SwiftPM, that list contains a scheme per resolved package and plugin, none of which can be a watch companion. Each probe takes ~2-3 seconds, so on a real project this added ~160s (60 probes) before the actual build started. This change restricts the fallback to schemes that have an .xcscheme file under the host Xcode project's xcshareddata/xcschemes/ directory, so SwiftPM package schemes are skipped without an xcodebuild call. Fixes flutter#186004
Addresses review feedback: the previous filter only checked Runner.xcodeproj/xcshareddata/xcschemes, which would falsely skip projects whose watch scheme is shared at the workspace level (Runner.xcworkspace/xcshareddata/xcschemes) instead. The host-shared check now passes when an .xcscheme file exists in either the project's or the workspace's xcshareddata/xcschemes directory. SwiftPM package schemes still appear in neither, so they continue to be skipped. Adds a test that places the scheme only at the workspace level and asserts that containsWatchCompanion finds it.
Moves SwiftPM scheme filtering into XcodeProjectInterpreter.getInfo so callers receive an XcodeProjectInfo that excludes Flutter-generated Swift package schemes, direct plugin scheme names, plugin dash variants, and transitive Swift package schemes discovered under SourcePackages checkouts. This keeps watch companion detection from probing SwiftPM package schemes while avoiding a host .xcscheme file requirement for valid non-shared project schemes. Adds getInfo coverage for direct plugin schemes and transitive .swiftpm schemes, and restores watch companion tests to exercise generic non-default scheme probing.
28d6b49 to
f9975fc
Compare
|
Thanks again for the heads-up about #186378 landing; I’ve now rebased onto the latest The filtering logic has been moved earlier, into
I’ve also removed the earlier shared-scheme filter from Local testing against my TimeFinder app showed the scheme count reduced significantly as expected (67 → 6), and correctly detecting the watch companion (TimeFinderWatchApp) without probing unrelated plugin schemes (Patrol, Amplitude-Swift, etc). Happy to address any needed revisions as quickly as I can. Thanks for the attention to this Victoria! |
vashworth
left a comment
There was a problem hiding this comment.
This looks really great! Thanks for working on it! I think it just needs some doc comments and then should be good to go
…-swiftpm-scheme-scan
Compare schemes parsed from `xcodebuild -list` against ignored scheme candidates case-insensitively instead of generating sentence-cased plugin variants. The ignored set still enumerates known plugin spellings (`snake_case` and dashed), while casing is handled at lookup time. Add comments explaining why the watch companion fallback excludes generated Flutter SwiftPM package schemes, plugin scheme-name candidates, and schemes contributed by transitive SwiftPM checkouts. Addresses review feedback on flutter#186006.
|
Thanks for the thoughtful review @vashworth; I believe I've addressed all the comments. Let me know if you have any other suggestions. Thank you! |
Roll Flutter from e03b91f1fe34 to f3a4b9897834 (63 revisions) flutter/flutter@e03b91f...f3a4b98 2026-05-26 47866232+chunhtai@users.noreply.github.com Update batch release doc to reflect latest workflow (flutter/flutter#186979) 2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from 0442274cc696 to 27a819894f7c (5 revisions) (flutter/flutter#187094) 2026-05-26 bkonyi@google.com [Tool Robustness] Gracefully handle asynchronous subprocess crashes and connection timeouts (flutter/flutter#186964) 2026-05-26 bkonyi@google.com [pubspec] Bump Dart SDK constraint to ^3.13.0 (flutter/flutter#186957) 2026-05-26 engine-flutter-autoroll@skia.org Roll Dart SDK from 7eb54169841d to 00e625453c43 (1 revision) (flutter/flutter#187086) 2026-05-26 bdero@google.com [Impeller] Retire Y-coord-scale plumbing by flipping GLES at the vertex stage (flutter/flutter#186556) 2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from f4f294bdf98d to 0442274cc696 (2 revisions) (flutter/flutter#187079) 2026-05-26 kevmoo@users.noreply.github.com [flutter_tools] Fix version cache poisoning from git environment variables (flutter/flutter#186595) 2026-05-26 bkonyi@google.com [Tool] Handle DTD connection failures gracefully in widget-preview (flutter/flutter#186952) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 9d1adb5f2427 to f4f294bdf98d (1 revision) (flutter/flutter#187056) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 4dd78179e6ec to 9d1adb5f2427 (1 revision) (flutter/flutter#187048) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 1f26101197bf to 4dd78179e6ec (4 revisions) (flutter/flutter#187044) 2026-05-24 engine-flutter-autoroll@skia.org Roll Skia from bbe9ccc2bdbf to 1f26101197bf (1 revision) (flutter/flutter#187016) 2026-05-24 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from nsgcNDlZOuweOvy3Q... to Itd2Jq_ZIABH2rW7B... (flutter/flutter#187032) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 7e0f28eb5315 to 7eb54169841d (1 revision) (flutter/flutter#187005) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 90e55fa88456 to 7e0f28eb5315 (1 revision) (flutter/flutter#186990) 2026-05-23 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 6T6BY9PTftoG3vP_1... to nsgcNDlZOuweOvy3Q... (flutter/flutter#186984) 2026-05-23 chris@bracken.jp iOS] Migrate VSyncClient to a pure Obj-C implementation (#186166) (flutter/flutter#186935) 2026-05-23 30870216+gaaclarke@users.noreply.github.com Disables embedder_tests.cm for fuchsia (flutter/flutter#186969) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from b8414c46f6c7 to 90e55fa88456 (2 revisions) (flutter/flutter#186977) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from 6fdb013d1953 to bbe9ccc2bdbf (1 revision) (flutter/flutter#186980) 2026-05-22 mdebbar@google.com [web] Fix cutoff text in WebParagraph (flutter/flutter#186819) 2026-05-22 1961493+harryterkelsen@users.noreply.github.com fix(web): Removes the iterative downscaling hack (flutter/flutter#186914) 2026-05-22 30870216+gaaclarke@users.noreply.github.com opts the linux embedder into sdf rendering (flutter/flutter#186909) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from dae8778ca40d to 6fdb013d1953 (5 revisions) (flutter/flutter#186970) 2026-05-22 dacoharkes@google.com Fix hooks inputs outputs rebuilt (flutter/flutter#186701) 2026-05-22 30870216+gaaclarke@users.noreply.github.com adds linux impeller integration test for external textures (flutter/flutter#186759) 2026-05-22 kevmoo@users.noreply.github.com fix(flutter_tools): defensively catch DWDS unregistered service extension errors (flutter/flutter#186896) 2026-05-22 bdero@google.com [Impeller] Add golden harness support to the renderer test layer (flutter/flutter#186735) 2026-05-22 mdebbar@google.com [web] Remove image codecs from canvaskit_chromium (flutter/flutter#178133) 2026-05-22 30870216+gaaclarke@users.noreply.github.com opts all macos into wide gamut (flutter/flutter#186277) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from 356185490a75 to dae8778ca40d (9 revisions) (flutter/flutter#186949) 2026-05-22 1598289+lukemmtt@users.noreply.github.com Filter out SwiftPM schemes when fetching schemes (flutter/flutter#186006) 2026-05-22 engine-flutter-autoroll@skia.org Roll Packages from 3754d04 to 69cf959 (1 revision) (flutter/flutter#186950) 2026-05-22 engine-flutter-autoroll@skia.org Roll Dart SDK from eca46bec956d to b8414c46f6c7 (2 revisions) (flutter/flutter#186944) 2026-05-22 30870216+gaaclarke@users.noreply.github.com Saves a DeviceHolderVK with the CommandPoolVK (flutter/flutter#186749) 2026-05-22 engine-flutter-autoroll@skia.org Roll Dart SDK from e0d509fd676e to eca46bec956d (1 revision) (flutter/flutter#186922) 2026-05-22 bkonyi@google.com [ Tool ] Stop generating widget preview scaffold under $TMP (flutter/flutter#186476) 2026-05-21 737941+loic-sharma@users.noreply.github.com Fix typo in StretchingOverscrollIndicator docs (flutter/flutter#186897) 2026-05-21 engine-flutter-autoroll@skia.org Roll Dart SDK from 28c7cb5a8e8d to e0d509fd676e (1 revision) (flutter/flutter#186903) 2026-05-21 jason-simmons@users.noreply.github.com Fix some issues in the integration between EmbedderExternalViewEmbedder and Impeller (flutter/flutter#184905) 2026-05-21 jason-simmons@users.noreply.github.com Fix a potential buffer overflow in the animated PNG decoder when parsing malformed fdAT chunks (flutter/flutter#186700) 2026-05-21 engine-flutter-autoroll@skia.org Roll Skia from 2ff20950975d to 356185490a75 (5 revisions) (flutter/flutter#186892) 2026-05-21 flar@google.com Add primitive shadows to rendering benchmark (flutter/flutter#186779) 2026-05-21 15619084+vashworth@users.noreply.github.com Move prefetchSwiftPackages to be per platform (flutter/flutter#186468) 2026-05-21 okorohelijah@google.com Upgrade iOS version (flutter/flutter#186889) ...
…r#11789) Roll Flutter from e03b91f1fe34 to f3a4b9897834 (63 revisions) flutter/flutter@e03b91f...f3a4b98 2026-05-26 47866232+chunhtai@users.noreply.github.com Update batch release doc to reflect latest workflow (flutter/flutter#186979) 2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from 0442274cc696 to 27a819894f7c (5 revisions) (flutter/flutter#187094) 2026-05-26 bkonyi@google.com [Tool Robustness] Gracefully handle asynchronous subprocess crashes and connection timeouts (flutter/flutter#186964) 2026-05-26 bkonyi@google.com [pubspec] Bump Dart SDK constraint to ^3.13.0 (flutter/flutter#186957) 2026-05-26 engine-flutter-autoroll@skia.org Roll Dart SDK from 7eb54169841d to 00e625453c43 (1 revision) (flutter/flutter#187086) 2026-05-26 bdero@google.com [Impeller] Retire Y-coord-scale plumbing by flipping GLES at the vertex stage (flutter/flutter#186556) 2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from f4f294bdf98d to 0442274cc696 (2 revisions) (flutter/flutter#187079) 2026-05-26 kevmoo@users.noreply.github.com [flutter_tools] Fix version cache poisoning from git environment variables (flutter/flutter#186595) 2026-05-26 bkonyi@google.com [Tool] Handle DTD connection failures gracefully in widget-preview (flutter/flutter#186952) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 9d1adb5f2427 to f4f294bdf98d (1 revision) (flutter/flutter#187056) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 4dd78179e6ec to 9d1adb5f2427 (1 revision) (flutter/flutter#187048) 2026-05-25 engine-flutter-autoroll@skia.org Roll Skia from 1f26101197bf to 4dd78179e6ec (4 revisions) (flutter/flutter#187044) 2026-05-24 engine-flutter-autoroll@skia.org Roll Skia from bbe9ccc2bdbf to 1f26101197bf (1 revision) (flutter/flutter#187016) 2026-05-24 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from nsgcNDlZOuweOvy3Q... to Itd2Jq_ZIABH2rW7B... (flutter/flutter#187032) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 7e0f28eb5315 to 7eb54169841d (1 revision) (flutter/flutter#187005) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 90e55fa88456 to 7e0f28eb5315 (1 revision) (flutter/flutter#186990) 2026-05-23 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 6T6BY9PTftoG3vP_1... to nsgcNDlZOuweOvy3Q... (flutter/flutter#186984) 2026-05-23 chris@bracken.jp iOS] Migrate VSyncClient to a pure Obj-C implementation (#186166) (flutter/flutter#186935) 2026-05-23 30870216+gaaclarke@users.noreply.github.com Disables embedder_tests.cm for fuchsia (flutter/flutter#186969) 2026-05-23 engine-flutter-autoroll@skia.org Roll Dart SDK from b8414c46f6c7 to 90e55fa88456 (2 revisions) (flutter/flutter#186977) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from 6fdb013d1953 to bbe9ccc2bdbf (1 revision) (flutter/flutter#186980) 2026-05-22 mdebbar@google.com [web] Fix cutoff text in WebParagraph (flutter/flutter#186819) 2026-05-22 1961493+harryterkelsen@users.noreply.github.com fix(web): Removes the iterative downscaling hack (flutter/flutter#186914) 2026-05-22 30870216+gaaclarke@users.noreply.github.com opts the linux embedder into sdf rendering (flutter/flutter#186909) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from dae8778ca40d to 6fdb013d1953 (5 revisions) (flutter/flutter#186970) 2026-05-22 dacoharkes@google.com Fix hooks inputs outputs rebuilt (flutter/flutter#186701) 2026-05-22 30870216+gaaclarke@users.noreply.github.com adds linux impeller integration test for external textures (flutter/flutter#186759) 2026-05-22 kevmoo@users.noreply.github.com fix(flutter_tools): defensively catch DWDS unregistered service extension errors (flutter/flutter#186896) 2026-05-22 bdero@google.com [Impeller] Add golden harness support to the renderer test layer (flutter/flutter#186735) 2026-05-22 mdebbar@google.com [web] Remove image codecs from canvaskit_chromium (flutter/flutter#178133) 2026-05-22 30870216+gaaclarke@users.noreply.github.com opts all macos into wide gamut (flutter/flutter#186277) 2026-05-22 engine-flutter-autoroll@skia.org Roll Skia from 356185490a75 to dae8778ca40d (9 revisions) (flutter/flutter#186949) 2026-05-22 1598289+lukemmtt@users.noreply.github.com Filter out SwiftPM schemes when fetching schemes (flutter/flutter#186006) 2026-05-22 engine-flutter-autoroll@skia.org Roll Packages from 3754d04 to 69cf959 (1 revision) (flutter/flutter#186950) 2026-05-22 engine-flutter-autoroll@skia.org Roll Dart SDK from eca46bec956d to b8414c46f6c7 (2 revisions) (flutter/flutter#186944) 2026-05-22 30870216+gaaclarke@users.noreply.github.com Saves a DeviceHolderVK with the CommandPoolVK (flutter/flutter#186749) 2026-05-22 engine-flutter-autoroll@skia.org Roll Dart SDK from e0d509fd676e to eca46bec956d (1 revision) (flutter/flutter#186922) 2026-05-22 bkonyi@google.com [ Tool ] Stop generating widget preview scaffold under $TMP (flutter/flutter#186476) 2026-05-21 737941+loic-sharma@users.noreply.github.com Fix typo in StretchingOverscrollIndicator docs (flutter/flutter#186897) 2026-05-21 engine-flutter-autoroll@skia.org Roll Dart SDK from 28c7cb5a8e8d to e0d509fd676e (1 revision) (flutter/flutter#186903) 2026-05-21 jason-simmons@users.noreply.github.com Fix some issues in the integration between EmbedderExternalViewEmbedder and Impeller (flutter/flutter#184905) 2026-05-21 jason-simmons@users.noreply.github.com Fix a potential buffer overflow in the animated PNG decoder when parsing malformed fdAT chunks (flutter/flutter#186700) 2026-05-21 engine-flutter-autoroll@skia.org Roll Skia from 2ff20950975d to 356185490a75 (5 revisions) (flutter/flutter#186892) 2026-05-21 flar@google.com Add primitive shadows to rendering benchmark (flutter/flutter#186779) 2026-05-21 15619084+vashworth@users.noreply.github.com Move prefetchSwiftPackages to be per platform (flutter/flutter#186468) 2026-05-21 okorohelijah@google.com Upgrade iOS version (flutter/flutter#186889) ...
## Summary In iOS projects with a watchOS companion target and Swift Package Manager enabled, `IosProject.containsWatchCompanion()` has a fallback path for modern Xcode projects where the companion relationship is declared through `INFOPLIST_KEY_WKCompanionAppBundleIdentifier` in `project.pbxproj`, rather than as a literal `WKCompanionAppBundleIdentifier` key in the watch target `Info.plist`. That fallback iterates `projectInfo.schemes` and runs: ```bash xcodebuild -showBuildSettings -destination generic/platform=watchOS ``` for each non-default scheme until it finds the watch companion scheme. With SwiftPM enabled, `xcodebuild -list` can include schemes for direct Flutter plugin packages and transitive Swift packages, such as `advertising-id`, `amplitude-flutter`, `Amplitude-Swift`, `RevenueCatUI`, and `SuperwallKit`. Those schemes cannot be the host project's watch companion, but each failed watchOS build-settings probe can take multiple seconds. This PR filters those non-host schemes earlier, in `XcodeProjectInterpreter.getInfo()`, before they become part of `XcodeProjectInfo.schemes`. The current filter excludes: - `FlutterGeneratedPluginSwiftPackage` - `FlutterFramework` - plugin names from `xcodeProject.getPlugins()` - dashed and capitalized plugin-name variants, e.g. `cloud_firestore`, `cloud-firestore`, `Cloud-firestore` - transitive SwiftPM package schemes found under `build/ios/SourcePackages/checkouts/*/.swiftpm/xcode/xcshareddata/xcschemes/*.xcscheme` I also removed the earlier shared-scheme-location filter from `containsWatchCompanion()`. That earlier approach was present in [0cfdd3a](flutter@0cfdd3a), but it could skip valid non-shared host schemes. The current approach keeps the fallback behavior scheme-based while removing known SwiftPM package schemes from the candidate list. Fixes flutter#186004. ## Measurements Test project: TimeFinder app. Command: ```bash flutter build ios --debug --simulator --no-pub -v ``` Benchmark condition for fallback rows: the literal `WKCompanionAppBundleIdentifier` key was removed from the watch target `Info.plist`, while the modern `INFOPLIST_KEY_WKCompanionAppBundleIdentifier` entries remained in `project.pbxproj`. | Scenario | Unique watchOS probes before detection | Time to detection, 3 trials | Median | Fallback scan only, 3 trials | Median | |---|---:|---:|---:|---:|---:| | Literal plist key present, no fallback | 0 | 92.8s, 70.0s, 70.9s | 70.9s | n/a | n/a | | Unpatched baseline, no plist key | 60 | 244.2s, 235.4s, 238.9s | 238.9s | 174.1s, 170.8s, 165.6s | 170.8s | | Earlier shared-scheme approach, no plist key | 5 | 90.2s, 89.8s, 87.7s | 89.8s | 16.9s, 21.0s, 17.6s | 17.6s | | Current PR, no plist key | 3 | 85.3s, 80.7s, 83.3s | 83.3s | 12.5s, 11.5s, 11.8s | 11.8s | In this project, Xcode listed 67 schemes. The current filter reduced that to 6 retained schemes, and the fallback reached `TimeFinderWatchApp` after probing only: - `LiveActivityWidgetExtension` - `ScheduleWidgetExtension` - `TimeFinderWatchApp` It did not probe direct plugin schemes or transitive SwiftPM package schemes, including `Patrol`, `Amplitude-Swift`, `RevenueCatUI`, `RevenueCatUITests`, or `SuperwallKit`. Worth noting: TimeFinder is a worst-case-ish benchmark project for this issue: it has many SwiftPM package schemes, and `xcodebuild -list` returns schemes alphabetically here, so `TimeFinderWatchApp` is near the end of the candidate sequence. A project with a watch scheme that sorts early, such as `AAAWatchApp`, would see far less baseline overhead and therefore less benefit from this PR. ## Test Plan - `flutter test test/general.shard/ios/xcodeproj_test.dart` - `flutter test test/general.shard/project_test.dart --plain-name 'watch companion'` - `flutter analyze` in `packages/flutter_tools` - `git diff --check` --------- Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Co-authored-by: Elijah Okoroh <okorohelijah@google.com>
Summary
In iOS projects with a watchOS companion target and Swift Package Manager enabled,
IosProject.containsWatchCompanion()has a fallback path for modern Xcode projects where the companion relationship is declared throughINFOPLIST_KEY_WKCompanionAppBundleIdentifierinproject.pbxproj, rather than as a literalWKCompanionAppBundleIdentifierkey in the watch targetInfo.plist.That fallback iterates
projectInfo.schemesand runs:for each non-default scheme until it finds the watch companion scheme.
With SwiftPM enabled,
xcodebuild -listcan include schemes for direct Flutter plugin packages and transitive Swift packages, such asadvertising-id,amplitude-flutter,Amplitude-Swift,RevenueCatUI, andSuperwallKit. Those schemes cannot be the host project's watch companion, but each failed watchOS build-settings probe can take multiple seconds.This PR filters those non-host schemes earlier, in
XcodeProjectInterpreter.getInfo(), before they become part ofXcodeProjectInfo.schemes.The current filter excludes:
FlutterGeneratedPluginSwiftPackageFlutterFrameworkxcodeProject.getPlugins()cloud_firestore,cloud-firestore,Cloud-firestorebuild/ios/SourcePackages/checkouts/*/.swiftpm/xcode/xcshareddata/xcschemes/*.xcschemeI also removed the earlier shared-scheme-location filter from
containsWatchCompanion(). That earlier approach was present in 0cfdd3a67c2, but it could skip valid non-shared host schemes. The current approach keeps the fallback behavior scheme-based while removing known SwiftPM package schemes from the candidate list.Fixes #186004.
Measurements
Test project: TimeFinder app.
Command:
Benchmark condition for fallback rows: the literal
WKCompanionAppBundleIdentifierkey was removed from the watch targetInfo.plist, while the modernINFOPLIST_KEY_WKCompanionAppBundleIdentifierentries remained inproject.pbxproj.In this project, Xcode listed 67 schemes. The current filter reduced that to 6 retained schemes, and the fallback reached
TimeFinderWatchAppafter probing only:LiveActivityWidgetExtensionScheduleWidgetExtensionTimeFinderWatchAppIt did not probe direct plugin schemes or transitive SwiftPM package schemes, including
Patrol,Amplitude-Swift,RevenueCatUI,RevenueCatUITests, orSuperwallKit.Worth noting: TimeFinder is a worst-case-ish benchmark project for this issue: it has many SwiftPM package schemes, and
xcodebuild -listreturns schemes alphabetically here, soTimeFinderWatchAppis near the end of the candidate sequence. A project with a watch scheme that sorts early, such asAAAWatchApp, would see far less baseline overhead and therefore less benefit from this PR.Test Plan
flutter test test/general.shard/ios/xcodeproj_test.dartflutter test test/general.shard/project_test.dart --plain-name 'watch companion'flutter analyzeinpackages/flutter_toolsgit diff --check