Skip to content

Commit 9b41640

Browse files
[tool] Don't write the .flutter-plugins-dependencies file if it is unchanged (#166164)
Currently, `refreshPlugins` always updates the `.flutter-plugins-dependencies` file. In a future change, `flutter assemble` will use the `.flutter-plugins-dependencies` file as an input. Unnecessary writes to this file will invalidate build targets. This updates the logic to only write .flutter-plugins-dependencies if it has "significant" changes. Part of flutter/flutter#163874 Next pull request: flutter/flutter#165916 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com>
1 parent f539bb4 commit 9b41640

File tree

2 files changed

+149
-52
lines changed

2 files changed

+149
-52
lines changed

packages/flutter_tools/lib/src/flutter_plugins.dart

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -234,26 +234,79 @@ bool _writeFlutterPluginsList(
234234
'macos': swiftPackageManagerEnabledMacos,
235235
};
236236

237-
// Only notify if the plugins list has changed. [date_created] will always be different,
238-
// [version] is not relevant for this check.
239-
final String? oldPluginsFileStringContent = _readFileContent(pluginsFile);
240-
bool pluginsChanged = true;
241-
if (oldPluginsFileStringContent != null) {
242-
try {
243-
final Object? decodedJson = jsonDecode(oldPluginsFileStringContent);
244-
if (decodedJson is Map<String, Object?>) {
245-
final String jsonOfNewPluginsMap = jsonEncode(pluginsMap);
246-
final String jsonOfOldPluginsMap = jsonEncode(decodedJson[_kFlutterPluginsPluginListKey]);
247-
pluginsChanged = jsonOfNewPluginsMap != jsonOfOldPluginsMap;
248-
}
249-
} on FormatException catch (_) {}
237+
// Only write the plugins file if its content have changed. This ensures
238+
// that flutter assemble targets that depend on this file aren't invalidated
239+
// unnecessarily.
240+
final (:bool pluginsChanged, :bool contentsChanged) = _detectFlutterPluginsListChanges(
241+
pluginsFile,
242+
result,
243+
);
244+
if (pluginsChanged || contentsChanged) {
245+
final String pluginFileContent = json.encode(result);
246+
pluginsFile.writeAsStringSync(pluginFileContent, flush: true);
250247
}
251-
final String pluginFileContent = json.encode(result);
252-
pluginsFile.writeAsStringSync(pluginFileContent, flush: true);
253248

254249
return pluginsChanged;
255250
}
256251

252+
/// Find what has changed in the .flutter-plugins-dependencies JSON file.
253+
///
254+
/// [pluginsChanged] is [true] if anything changed in the 'plugins' property.
255+
/// This indicates that platform-specific tooling like 'pod install' should be
256+
/// re-run.
257+
///
258+
/// [contentsChanged] is [true] if [newJson] has changes that should be saved to
259+
/// disk.
260+
({bool pluginsChanged, bool contentsChanged}) _detectFlutterPluginsListChanges(
261+
File pluginsFile,
262+
Map<String, Object> newJson,
263+
) {
264+
final String? oldPluginsFileStringContent = _readFileContent(pluginsFile);
265+
if (oldPluginsFileStringContent == null) {
266+
return (pluginsChanged: true, contentsChanged: true);
267+
}
268+
269+
try {
270+
final Object? oldJson = jsonDecode(oldPluginsFileStringContent);
271+
if (oldJson is! Map<String, Object?>) {
272+
return (pluginsChanged: true, contentsChanged: true);
273+
}
274+
275+
// Check if plugins changed.
276+
final String jsonOfNewPluginsMap = jsonEncode(newJson[_kFlutterPluginsPluginListKey]);
277+
final String jsonOfOldPluginsMap = jsonEncode(oldJson[_kFlutterPluginsPluginListKey]);
278+
if (jsonOfNewPluginsMap != jsonOfOldPluginsMap) {
279+
return (pluginsChanged: true, contentsChanged: true);
280+
}
281+
282+
// Create a copy of the new JSON so that the input isn't mutated when we
283+
// drop properties that should be ignored.
284+
final Map<String, Object?> newJsonCopy = <String, Object?>{...newJson};
285+
286+
// The 'info' property is a comment that doesn't affect functionality.
287+
// The 'dependencyGraph' property is deprecated and shouldn't be used.
288+
// The 'date_created' property is always updated.
289+
// The 'plugins' property has already been checked by the logic above.
290+
const List<String> ignoredKeys = <String>[
291+
'info',
292+
'dependencyGraph',
293+
'date_created',
294+
_kFlutterPluginsPluginListKey,
295+
];
296+
for (final String key in ignoredKeys) {
297+
oldJson.remove(key);
298+
newJsonCopy.remove(key);
299+
}
300+
301+
final String old = jsonEncode(oldJson);
302+
final String updated = jsonEncode(newJsonCopy);
303+
304+
return (pluginsChanged: false, contentsChanged: old != updated);
305+
} on FormatException catch (_) {
306+
return (pluginsChanged: true, contentsChanged: true);
307+
}
308+
}
309+
257310
/// Creates a map representation of the [plugins] for those supported by [platformKey].
258311
/// All given [plugins] must provide an implementation for the [platformKey].
259312
List<Map<String, Object>> _createPluginMapOfPlatform(List<Plugin> plugins, String platformKey) {

0 commit comments

Comments
 (0)