Unverified Commit bcd0959a authored by stuartmorgan's avatar stuartmorgan Committed by GitHub

Sort generated plugin file content by plugin name (#65509)

parent 5b76b350
...@@ -1161,6 +1161,8 @@ Future<void> refreshPluginsList(FlutterProject project, {bool checkProjects = fa ...@@ -1161,6 +1161,8 @@ Future<void> refreshPluginsList(FlutterProject project, {bool checkProjects = fa
/// Assumes [refreshPluginsList] has been called since last change to `pubspec.yaml`. /// Assumes [refreshPluginsList] has been called since last change to `pubspec.yaml`.
Future<void> injectPlugins(FlutterProject project, {bool checkProjects = false}) async { Future<void> injectPlugins(FlutterProject project, {bool checkProjects = false}) async {
final List<Plugin> plugins = await findPlugins(project); final List<Plugin> plugins = await findPlugins(project);
// Sort the plugins by name to keep ordering stable in generated files.
plugins.sort((Plugin left, Plugin right) => left.name.compareTo(right.name));
if ((checkProjects && project.android.existsSync()) || !checkProjects) { if ((checkProjects && project.android.existsSync()) || !checkProjects) {
await _writeAndroidPluginRegistrant(project, plugins); await _writeAndroidPluginRegistrant(project, plugins);
} }
......
...@@ -8,6 +8,7 @@ import 'package:file/file.dart'; ...@@ -8,6 +8,7 @@ import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart'; import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
...@@ -122,37 +123,57 @@ void main() { ...@@ -122,37 +123,57 @@ void main() {
); );
}); });
const String _pluginYaml = ''' // Makes fake plugin packages for each plugin, adds them to flutterProject,
// and returns their directories.
//
// If an entry contains a path separator, it will be treated as a path for
// the location of the package, with the name being the last component.
// Otherwise it will be treated as a name, and put in a default location
// (a fake pub cache).
List<Directory> createFakePlugins(FileSystem fileSystem, List<String> pluginNamesOrPaths) {
const String pluginYamlTemplate = '''
flutter: flutter:
plugin: plugin:
platforms: platforms:
ios: ios:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
macos: macos:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
windows: windows:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
linux: linux:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
web: web:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
fileName: lib/SomeFile.dart fileName: lib/PLUGIN_CLASS.dart
android: android:
pluginClass: SomePlugin pluginClass: PLUGIN_CLASS
package: AndroidPackage package: AndroidPackage
'''; ''';
final List<Directory> directories = <Directory>[];
final Directory fakePubCache = fileSystem.systemTempDirectory.childDirectory('cache');
final File packagesFile = flutterProject.directory.childFile('.packages')
..createSync(recursive: true);
for (final String nameOrPath in pluginNamesOrPaths) {
final String name = fileSystem.path.basename(nameOrPath);
final Directory pluginDirectory = (nameOrPath == name)
? fakePubCache.childDirectory(name)
: fileSystem.directory(nameOrPath);
packagesFile.writeAsStringSync(
'$name:file://${pluginDirectory.childFile('lib').uri}\n',
mode: FileMode.writeOnlyAppend);
pluginDirectory.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync(pluginYamlTemplate.replaceAll('PLUGIN_CLASS', toTitleCase(camelCase(name))));
directories.add(pluginDirectory);
}
return directories;
}
// Makes a fake plugin package, adds it to flutterProject, and returns its directory. // Makes a fake plugin package, adds it to flutterProject, and returns its directory.
Directory createFakePlugin(FileSystem fileSystem) { Directory createFakePlugin(FileSystem fileSystem) {
const String name = 'apackage'; return createFakePlugins(fileSystem, <String>['some_plugin'])[0];
final Directory packageDirectory = fileSystem.systemTempDirectory.childDirectory('cache').childDirectory(name);
flutterProject.directory.childFile('.packages')
..createSync(recursive: true)
..writeAsStringSync('$name:file://${packageDirectory.childFile('lib').uri}\n');
packageDirectory.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync(_pluginYaml);
return packageDirectory;
} }
void createNewJavaPlugin1() { void createNewJavaPlugin1() {
...@@ -1034,7 +1055,7 @@ flutter: ...@@ -1034,7 +1055,7 @@ flutter:
expect(pluginMakefile.existsSync(), isTrue); expect(pluginMakefile.existsSync(), isTrue);
final String contents = pluginMakefile.readAsStringSync(); final String contents = pluginMakefile.readAsStringSync();
expect(contents, contains('apackage')); expect(contents, contains('some_plugin'));
expect(contents, contains('target_link_libraries(\${BINARY_NAME} PRIVATE \${plugin}_plugin)')); expect(contents, contains('target_link_libraries(\${BINARY_NAME} PRIVATE \${plugin}_plugin)'));
expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \$<TARGET_FILE:\${plugin}_plugin>)')); expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \$<TARGET_FILE:\${plugin}_plugin>)'));
expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \${\${plugin}_bundled_libraries})')); expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \${\${plugin}_bundled_libraries})'));
...@@ -1044,6 +1065,32 @@ flutter: ...@@ -1044,6 +1065,32 @@ flutter:
FeatureFlags: () => featureFlags, FeatureFlags: () => featureFlags,
}); });
testUsingContext('Generated Linux plugin files sorts by plugin name', () async {
when(linuxProject.existsSync()).thenReturn(true);
when(featureFlags.isLinuxEnabled).thenReturn(true);
when(flutterProject.isModule).thenReturn(false);
createFakePlugins(fs, <String>[
'plugin_d',
'plugin_a',
'/local_plugins/plugin_c',
'/local_plugins/plugin_b'
]);
await injectPlugins(flutterProject, checkProjects: true);
final File pluginCmakeFile = linuxProject.generatedPluginCmakeFile;
final File pluginRegistrant = linuxProject.managedDirectory.childFile('generated_plugin_registrant.cc');
for (final File file in <File>[pluginCmakeFile, pluginRegistrant]) {
final String contents = file.readAsStringSync();
expect(contents.indexOf('plugin_a'), lessThan(contents.indexOf('plugin_b')));
expect(contents.indexOf('plugin_b'), lessThan(contents.indexOf('plugin_c')));
expect(contents.indexOf('plugin_c'), lessThan(contents.indexOf('plugin_d')));
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => featureFlags,
});
testUsingContext('Injecting creates generated Windows registrant', () async { testUsingContext('Injecting creates generated Windows registrant', () async {
when(windowsProject.existsSync()).thenReturn(true); when(windowsProject.existsSync()).thenReturn(true);
...@@ -1119,22 +1166,27 @@ flutter: ...@@ -1119,22 +1166,27 @@ flutter:
FeatureFlags: () => featureFlags, FeatureFlags: () => featureFlags,
}); });
testUsingContext('Injecting creates generated Windows plugin CMake file', () async { testUsingContext('Generated Windows plugin files sorts by plugin name', () async {
when(windowsProject.existsSync()).thenReturn(true); when(windowsProject.existsSync()).thenReturn(true);
when(featureFlags.isWindowsEnabled).thenReturn(true); when(featureFlags.isWindowsEnabled).thenReturn(true);
when(flutterProject.isModule).thenReturn(false); when(flutterProject.isModule).thenReturn(false);
createFakePlugin(fs); createFakePlugins(fs, <String>[
'plugin_d',
'plugin_a',
'/local_plugins/plugin_c',
'/local_plugins/plugin_b'
]);
await injectPlugins(flutterProject, checkProjects: true); await injectPlugins(flutterProject, checkProjects: true);
final File pluginMakefile = windowsProject.generatedPluginCmakeFile; final File pluginCmakeFile = windowsProject.generatedPluginCmakeFile;
final File pluginRegistrant = windowsProject.managedDirectory.childFile('generated_plugin_registrant.cc');
expect(pluginMakefile.existsSync(), isTrue); for (final File file in <File>[pluginCmakeFile, pluginRegistrant]) {
final String contents = pluginMakefile.readAsStringSync(); final String contents = file.readAsStringSync();
expect(contents, contains('apackage')); expect(contents.indexOf('plugin_a'), lessThan(contents.indexOf('plugin_b')));
expect(contents, contains('target_link_libraries(\${BINARY_NAME} PRIVATE \${plugin}_plugin)')); expect(contents.indexOf('plugin_b'), lessThan(contents.indexOf('plugin_c')));
expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \$<TARGET_FILE:\${plugin}_plugin>)')); expect(contents.indexOf('plugin_c'), lessThan(contents.indexOf('plugin_d')));
expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \${\${plugin}_bundled_libraries})')); }
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
...@@ -1183,7 +1235,7 @@ flutter: ...@@ -1183,7 +1235,7 @@ flutter:
// refreshPluginsList should call createPluginSymlinks. // refreshPluginsList should call createPluginSymlinks.
await refreshPluginsList(flutterProject); await refreshPluginsList(flutterProject);
expect(linuxProject.pluginSymlinkDirectory.childLink('apackage').existsSync(), true); expect(linuxProject.pluginSymlinkDirectory.childLink('some_plugin').existsSync(), true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
...@@ -1196,7 +1248,7 @@ flutter: ...@@ -1196,7 +1248,7 @@ flutter:
// refreshPluginsList should call createPluginSymlinks. // refreshPluginsList should call createPluginSymlinks.
await refreshPluginsList(flutterProject); await refreshPluginsList(flutterProject);
expect(windowsProject.pluginSymlinkDirectory.childLink('apackage').existsSync(), true); expect(windowsProject.pluginSymlinkDirectory.childLink('some_plugin').existsSync(), true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
...@@ -1282,8 +1334,8 @@ flutter: ...@@ -1282,8 +1334,8 @@ flutter:
await refreshPluginsList(flutterProject); await refreshPluginsList(flutterProject);
final List<Link> links = <Link>[ final List<Link> links = <Link>[
linuxProject.pluginSymlinkDirectory.childLink('apackage'), linuxProject.pluginSymlinkDirectory.childLink('some_plugin'),
windowsProject.pluginSymlinkDirectory.childLink('apackage'), windowsProject.pluginSymlinkDirectory.childLink('some_plugin'),
]; ];
for (final Link link in links) { for (final Link link in links) {
link.deleteSync(); link.deleteSync();
...@@ -1318,7 +1370,26 @@ flutter: ...@@ -1318,7 +1370,26 @@ flutter:
} }
test('validatePubspecForPlugin works', () async { test('validatePubspecForPlugin works', () async {
_createPubspecFile(_pluginYaml); const String pluginYaml = '''
flutter:
plugin:
platforms:
ios:
pluginClass: SomePlugin
macos:
pluginClass: SomePlugin
windows:
pluginClass: SomePlugin
linux:
pluginClass: SomePlugin
web:
pluginClass: SomePlugin
fileName: lib/SomeFile.dart
android:
pluginClass: SomePlugin
package: AndroidPackage
''';
_createPubspecFile(pluginYaml);
validatePubspecForPlugin(projectDir: projectDir.absolute.path, pluginClass: 'SomePlugin', expectedPlatforms: <String>[ validatePubspecForPlugin(projectDir: projectDir.absolute.path, pluginClass: 'SomePlugin', expectedPlatforms: <String>[
'ios', 'macos', 'windows', 'linux', 'android', 'web' 'ios', 'macos', 'windows', 'linux', 'android', 'web'
], androidIdentifier: 'AndroidPackage', webFileName: 'lib/SomeFile.dart'); ], androidIdentifier: 'AndroidPackage', webFileName: 'lib/SomeFile.dart');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment