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
/// Assumes [refreshPluginsList] has been called since last change to `pubspec.yaml`.
Future<void> injectPlugins(FlutterProject project, {bool checkProjects = false}) async {
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) {
await _writeAndroidPluginRegistrant(project, plugins);
}
......
......@@ -8,6 +8,7 @@ import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.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/globals.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart';
......@@ -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:
plugin:
platforms:
ios:
pluginClass: SomePlugin
pluginClass: PLUGIN_CLASS
macos:
pluginClass: SomePlugin
pluginClass: PLUGIN_CLASS
windows:
pluginClass: SomePlugin
pluginClass: PLUGIN_CLASS
linux:
pluginClass: SomePlugin
pluginClass: PLUGIN_CLASS
web:
pluginClass: SomePlugin
fileName: lib/SomeFile.dart
pluginClass: PLUGIN_CLASS
fileName: lib/PLUGIN_CLASS.dart
android:
pluginClass: SomePlugin
pluginClass: PLUGIN_CLASS
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.
Directory createFakePlugin(FileSystem fileSystem) {
const String name = 'apackage';
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;
return createFakePlugins(fileSystem, <String>['some_plugin'])[0];
}
void createNewJavaPlugin1() {
......@@ -1034,7 +1055,7 @@ flutter:
expect(pluginMakefile.existsSync(), isTrue);
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('list(APPEND PLUGIN_BUNDLED_LIBRARIES \$<TARGET_FILE:\${plugin}_plugin>)'));
expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \${\${plugin}_bundled_libraries})'));
......@@ -1044,6 +1065,32 @@ flutter:
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 {
when(windowsProject.existsSync()).thenReturn(true);
......@@ -1119,22 +1166,27 @@ flutter:
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(featureFlags.isWindowsEnabled).thenReturn(true);
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);
final File pluginMakefile = windowsProject.generatedPluginCmakeFile;
expect(pluginMakefile.existsSync(), isTrue);
final String contents = pluginMakefile.readAsStringSync();
expect(contents, contains('apackage'));
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 \${\${plugin}_bundled_libraries})'));
final File pluginCmakeFile = windowsProject.generatedPluginCmakeFile;
final File pluginRegistrant = windowsProject.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(),
......@@ -1183,7 +1235,7 @@ flutter:
// refreshPluginsList should call createPluginSymlinks.
await refreshPluginsList(flutterProject);
expect(linuxProject.pluginSymlinkDirectory.childLink('apackage').existsSync(), true);
expect(linuxProject.pluginSymlinkDirectory.childLink('some_plugin').existsSync(), true);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -1196,7 +1248,7 @@ flutter:
// refreshPluginsList should call createPluginSymlinks.
await refreshPluginsList(flutterProject);
expect(windowsProject.pluginSymlinkDirectory.childLink('apackage').existsSync(), true);
expect(windowsProject.pluginSymlinkDirectory.childLink('some_plugin').existsSync(), true);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -1282,8 +1334,8 @@ flutter:
await refreshPluginsList(flutterProject);
final List<Link> links = <Link>[
linuxProject.pluginSymlinkDirectory.childLink('apackage'),
windowsProject.pluginSymlinkDirectory.childLink('apackage'),
linuxProject.pluginSymlinkDirectory.childLink('some_plugin'),
windowsProject.pluginSymlinkDirectory.childLink('some_plugin'),
];
for (final Link link in links) {
link.deleteSync();
......@@ -1318,7 +1370,26 @@ flutter:
}
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>[
'ios', 'macos', 'windows', 'linux', 'android', 'web'
], 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