Automatically add plugin projects to Windows .sln (#51246)
Adds utility code for managing list of plugin projects within a solution file, updating them as the plugins change.
This is a prototype of an approach to solution-level portion of Windows plugin tooling; it may not be what the final plugin handling on Windows uses, but it makes things much better in the short term, and gives us a baseline to evaluate other possible solution management systems against.
Part of #32719
diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart
index 63f25b7..7fb5e87 100644
--- a/packages/flutter_tools/test/general.shard/plugins_test.dart
+++ b/packages/flutter_tools/test/general.shard/plugins_test.dart
@@ -76,6 +76,7 @@
final Directory windowsManagedDirectory = flutterProject.directory.childDirectory('windows').childDirectory('flutter');
when(windowsProject.managedDirectory).thenReturn(windowsManagedDirectory);
when(windowsProject.vcprojFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.vcxproj'));
+ when(windowsProject.solutionFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.sln'));
when(windowsProject.pluginSymlinkDirectory).thenReturn(windowsManagedDirectory.childDirectory('ephemeral').childDirectory('.plugin_symlinks'));
when(windowsProject.generatedPluginPropertySheetFile).thenReturn(windowsManagedDirectory.childFile('GeneratedPlugins.props'));
when(windowsProject.existsSync()).thenReturn(false);
@@ -309,6 +310,44 @@
project.podManifestLock.createSync(recursive: true);
}
+ // Creates a Windows solution file sufficient to allow plugin injection
+ // to run without failing.
+ void createDummyWindowsSolutionFile() {
+ windowsProject.solutionFile.createSync(recursive: true);
+ // This isn't a valid solution file, but it's just enough to work with the
+ // plugin injection.
+ windowsProject.solutionFile.writeAsStringSync('''
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{3842E94C-E348-463A-ADBE-625A2B69B628}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ EndGlobalSection
+EndGlobal''');
+ }
+
+ // Creates a Windows project file for dummyPackageDirectory sufficient to
+ // allow plugin injection to run without failing.
+ void createDummyPluginWindowsProjectFile() {
+ final File projectFile = dummyPackageDirectory
+ .parent
+ .childDirectory('windows')
+ .childFile('plugin.vcxproj');
+ projectFile.createSync(recursive: true);
+ // This isn't a valid project file, but it's just enough to work with the
+ // plugin injection.
+ projectFile.writeAsStringSync('''
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5919689F-A5D5-462C-AF50-D405CCEF89B8}</ProjectGuid>'}
+ <ProjectName>apackage</ProjectName>
+ </PropertyGroup>
+</Project>''');
+ }
+
group('refreshPlugins', () {
testUsingContext('Refreshing the plugin list is a no-op when the plugins list stays empty', () {
refreshPluginsList(flutterProject);
@@ -837,6 +876,8 @@
when(featureFlags.isWindowsEnabled).thenReturn(true);
when(flutterProject.isModule).thenReturn(false);
configureDummyPackageAsPlugin();
+ createDummyWindowsSolutionFile();
+ createDummyPluginWindowsProjectFile();
await injectPlugins(flutterProject, checkProjects: true);
@@ -857,6 +898,8 @@
when(featureFlags.isWindowsEnabled).thenReturn(true);
when(flutterProject.isModule).thenReturn(false);
configureDummyPackageAsPlugin();
+ createDummyWindowsSolutionFile();
+ createDummyPluginWindowsProjectFile();
await injectPlugins(flutterProject, checkProjects: true);
@@ -871,6 +914,23 @@
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => featureFlags,
});
+
+ testUsingContext('Injecting updates Windows solution file', () async {
+ when(windowsProject.existsSync()).thenReturn(true);
+ when(featureFlags.isWindowsEnabled).thenReturn(true);
+ when(flutterProject.isModule).thenReturn(false);
+ configureDummyPackageAsPlugin();
+ createDummyWindowsSolutionFile();
+ createDummyPluginWindowsProjectFile();
+
+ await injectPlugins(flutterProject, checkProjects: true);
+
+ expect(windowsProject.solutionFile.readAsStringSync(), contains(r'apackage\windows\plugin.vcxproj'));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => FakeProcessManager.any(),
+ FeatureFlags: () => featureFlags,
+ });
});
group('createPluginSymlinks', () {