[flutter_releases] Flutter stable 2.10.3 Framework Cherrypicks (#99337)

* Work around VS CMake generation bug (#98945)

* 'add branch flutter-2.8-candidate.16 to enabled_branches in .ci.yaml'

* 'Update Engine revision to bd539267b42051b0da3d16ffa8f48949dce8aa8f for stable release 2.10.3'

* remove branch ref

* remove consumer deps test

Co-authored-by: stuartmorgan <stuart.morgan@gmail.com>
Co-authored-by: Christopher Fujino <christopherfujino@gmail.com>
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index 62c80a8..8bde045 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-a83ed0e5e3b9cd2b5e2f07ef31c72f43c55e93b7
+bd539267b42051b0da3d16ffa8f48949dce8aa8f
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 131fb14..7bb3132 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -17,7 +17,6 @@
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
 
-import 'allowlist.dart';
 import 'run_command.dart';
 import 'utils.dart';
 
@@ -1495,51 +1494,9 @@
 }
 
 Future<void> _checkConsumerDependencies() async {
-  final ProcessResult result = await Process.run(flutter, <String>[
-    'update-packages',
-    '--transitive-closure',
-    '--consumer-only',
-  ]);
-  if (result.exitCode != 0) {
-    print(result.stdout as Object);
-    print(result.stderr as Object);
-    exit(result.exitCode);
-  }
-  final Set<String> dependencies = <String>{};
-  for (final String line in result.stdout.toString().split('\n')) {
-    if (!line.contains('->')) {
-      continue;
-    }
-    final List<String> parts = line.split('->');
-    final String name = parts[0].trim();
-    dependencies.add(name);
-  }
-
-  final Set<String> removed = kCorePackageAllowList.difference(dependencies);
-  final Set<String> added = dependencies.difference(kCorePackageAllowList);
-
-  String plural(int n, String s, String p) => n == 1 ? s : p;
-
-  if (added.isNotEmpty) {
-    exitWithError(<String>[
-      'The transitive closure of package dependencies contains ${plural(added.length, "a non-allowlisted package", "non-allowlisted packages")}:',
-      '  ${added.join(', ')}',
-      'We strongly desire to keep the number of dependencies to a minimum and',
-      'therefore would much prefer not to add new dependencies.',
-      'See dev/bots/allowlist.dart for instructions on how to update the package',
-      'allowlist if you nonetheless believe this is a necessary addition.',
-    ]);
-  }
-
-  if (removed.isNotEmpty) {
-    exitWithError(<String>[
-      'Excellent news! ${plural(removed.length, "A package dependency has been removed!", "Multiple package dependencies have been removed!")}',
-      '  ${removed.join(', ')}',
-      'To make sure we do not accidentally add ${plural(removed.length, "this dependency", "these dependencies")} back in the future,',
-      'please remove ${plural(removed.length, "this", "these")} packages from the allow-list in dev/bots/allowlist.dart.',
-      'Thanks!',
-    ]);
-  }
+  // Skipping this test for releases as it was never intended to work on release
+  // branches, and would fail for the 2.10 releases. See
+  // https://github.com/flutter/flutter/issues/91757.
 }
 
 const String _kDebugOnlyAnnotation = '@_debugOnly';
diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart
index 6422d39..859b97c 100644
--- a/packages/flutter_tools/lib/src/windows/build_windows.dart
+++ b/packages/flutter_tools/lib/src/windows/build_windows.dart
@@ -74,6 +74,9 @@
       buildDir: buildDirectory,
       sourceDir: windowsProject.cmakeFile.parent,
     );
+    if (visualStudio.displayVersion == '17.1.0') {
+      _fixBrokenCmakeGeneration(buildDirectory);
+    }
     await _runBuild(cmakePath, buildDirectory, buildModeName);
   } finally {
     status.cancel();
@@ -335,3 +338,55 @@
   }
   writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, environment);
 }
+
+// Works around the Visual Studio 17.1.0 CMake bug described in
+// https://github.com/flutter/flutter/issues/97086
+//
+// Rather than attempt to remove all the duplicate entries within the
+// <CustomBuild> element, which would require a more complicated parser, this
+// just fixes the incorrect duplicates to have the correct `$<CONFIG>` value,
+// making the duplication harmless.
+//
+// TODO(stuartmorgan): Remove this workaround either once 17.1.0 is
+// sufficiently old that we no longer need to support it, or when
+// dropping VS 2022 support.
+void _fixBrokenCmakeGeneration(Directory buildDirectory) {
+  final File assembleProject = buildDirectory
+    .childDirectory('flutter')
+    .childFile('flutter_assemble.vcxproj');
+  if (assembleProject.existsSync()) {
+    // E.g.: <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    final RegExp commandRegex = RegExp(
+      r'<Command Condition=.*\(Configuration\)\|\$\(Platform\).==.(Debug|Profile|Release)\|');
+    // E.g.: [...]/flutter_tools/bin/tool_backend.bat windows-x64 Debug
+    final RegExp assembleCallRegex = RegExp(
+      r'^.*/tool_backend\.bat windows[^ ]* (Debug|Profile|Release)');
+    String? lastCommandConditionConfig;
+    final StringBuffer newProjectContents = StringBuffer();
+    // vcxproj files contain a BOM, which readAsLinesSync drops; re-add it.
+    newProjectContents.writeCharCode(unicodeBomCharacterRune);
+    for (final String line in assembleProject.readAsLinesSync()) {
+      final RegExpMatch? commandMatch = commandRegex.firstMatch(line);
+      if (commandMatch != null) {
+        lastCommandConditionConfig = commandMatch.group(1);
+      } else if (lastCommandConditionConfig != null) {
+        final RegExpMatch? assembleCallMatch = assembleCallRegex.firstMatch(line);
+        if (assembleCallMatch != null) {
+          final String callConfig = assembleCallMatch.group(1)!;
+          if (callConfig != lastCommandConditionConfig) {
+            // The config is the end of the line; make sure to replace that one,
+            // in case config-matching strings appear anywhere else in the line
+            // (e.g., the project path).
+            final int badConfigIndex = line.lastIndexOf(assembleCallMatch.group(1)!);
+            final String correctedLine = line.replaceFirst(
+              callConfig, lastCommandConditionConfig, badConfigIndex);
+            newProjectContents.writeln('$correctedLine\r');
+            continue;
+          }
+        }
+      }
+      newProjectContents.writeln('$line\r');
+    }
+    assembleProject.writeAsStringSync(newProjectContents.toString());
+  }
+}
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
index a85bec4..66e5aed 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
@@ -309,6 +309,142 @@
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
 
+  testUsingContext('Windows build works around CMake generation bug', () async {
+    final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(displayVersion: '17.1.0');
+    final BuildWindowsCommand command = BuildWindowsCommand()
+      ..visualStudioOverride = fakeVisualStudio;
+    setUpMockProjectFilesForBuild();
+
+    processManager = FakeProcessManager.list(<FakeCommand>[
+      cmakeGenerationCommand(),
+      buildCommand('Release'),
+    ]);
+    fileSystem.file(fileSystem.path.join('lib', 'other.dart'))
+      .createSync(recursive: true);
+    fileSystem.file(fileSystem.path.join('foo', 'bar.sksl.json'))
+      .createSync(recursive: true);
+
+    // Relevant portions of an incorrectly generated project, with some
+    // irrelevant details removed for length.
+    const String fakeBadProjectContent = r'''
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <CustomBuild Include="somepath\build\windows\CMakeFiles\8b570225f626c250e12bc1ede88babae\flutter_windows.dll.rule">
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
+"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
+endlocal &amp; call :cmErrorLevel %errorlevel% &amp; goto :cmDone
+:cmErrorLevel
+exit /b %1
+:cmDone
+if %errorlevel% neq 0 goto :VCEnd</Command>
+    </CustomBuild>
+  </ItemGroup>
+</Project>
+''';
+    final File assembleProject = fileSystem.currentDirectory
+      .childDirectory('build')
+      .childDirectory('windows')
+      .childDirectory('flutter')
+      .childFile('flutter_assemble.vcxproj');
+    assembleProject.createSync(recursive: true);
+    assembleProject.writeAsStringSync(fakeBadProjectContent);
+
+    await createTestCommandRunner(command).run(
+      const <String>['windows', '--no-pub']
+    );
+
+    final List<String> projectLines = assembleProject.readAsLinesSync();
+
+    const String commandBase = r'"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" '
+      r'-E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64';
+    // The duplicate commands will still be present, but with the order matching
+    // the condition order (cycling through the configurations), rather than
+    // three copies of Debug, then three copies of Profile, then three copies
+    // of Release.
+    expect(projectLines, containsAllInOrder(<String>[
+      '$commandBase Debug\r',
+      '$commandBase Profile\r',
+      '$commandBase Release\r',
+      '$commandBase Debug\r',
+      '$commandBase Profile\r',
+      '$commandBase Release\r',
+      '$commandBase Debug\r',
+      '$commandBase Profile\r',
+      '$commandBase Release\r',
+    ]));
+  }, overrides: <Type, Generator>{
+    FileSystem: () => fileSystem,
+    ProcessManager: () => processManager,
+    Platform: () => windowsPlatform,
+    FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
+  });
+
   testUsingContext('Windows build invokes build and writes generated files', () async {
     final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
     final BuildWindowsCommand command = BuildWindowsCommand()
@@ -604,6 +740,7 @@
   FakeVisualStudio({
     this.cmakePath = _cmakePath,
     this.cmakeGenerator = 'Visual Studio 16 2019',
+    this.displayVersion = '17.0.0'
   });
 
   @override
@@ -611,4 +748,7 @@
 
   @override
   final String cmakeGenerator;
+
+  @override
+  final String displayVersion;
 }