diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index c38cf12df2..e46924edd0 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -19,12 +19,29 @@ import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; import 'visual_studio.dart'; +// These characters appear to be fine: @%()-+_{}[]`~ +const String _kBadCharacters = r"'#!$^&*=|,;<>?"; + /// Builds the Windows project using msbuild. Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { String? target, VisualStudio? visualStudioOverride, SizeAnalyzer? sizeAnalyzer, }) async { + // MSBuild files generated by CMake do not properly escape some characters + // In the directories. This check produces more meaningful error messages + // on failure as pertains to https://github.com/flutter/flutter/issues/104802 + final String projectPath = windowsProject.parent.directory.absolute.path; + final bool badPath = _kBadCharacters.runes + .any((int i) => projectPath.contains(String.fromCharCode(i))); + if (badPath) { + throwToolExit( + 'Path $projectPath contains invalid characters in "$_kBadCharacters". ' + 'Please rename your directory so as to not include any of these characters ' + 'and retry.', + ); + } + if (!windowsProject.cmakeFile.existsSync()) { throwToolExit( 'No Windows desktop project configured. See ' 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 cb1696b687..f702f87980 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 @@ -21,9 +21,11 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; const String flutterRoot = r'C:\flutter'; -const String buildFilePath = r'C:\windows\CMakeLists.txt'; -const String visualStudioPath = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community'; -const String _cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'; +const String buildFilePath = r'windows\CMakeLists.txt'; +const String visualStudioPath = + r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community'; +const String _cmakePath = visualStudioPath + + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'; const String _defaultGenerator = 'Visual Studio 16 2019'; final Platform windowsPlatform = FakePlatform( @@ -80,7 +82,7 @@ void main() { command: [ _cmakePath, '-S', - fileSystem.path.dirname(buildFilePath), + fileSystem.path.absolute(fileSystem.path.dirname(buildFilePath)), '-B', r'build\windows', '-G', @@ -923,7 +925,7 @@ if %errorlevel% neq 0 goto :VCEnd expect(testLogger.statusText, contains('A summary of your Windows bundle analysis can be found at')); expect(testLogger.statusText, contains('flutter pub global activate devtools; flutter pub global run devtools --appSizeBase=')); expect(usage.events, contains( - const TestUsageEvent('code-size-analysis', 'windows'), + const TestUsageEvent('code-size-analysis', 'windows'), )); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), @@ -933,6 +935,35 @@ if %errorlevel% neq 0 goto :VCEnd FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), Usage: () => usage, }); + + // Confirms that running for Windows in a directory with a + // bad character (' in this case) throws the desired error message + // If the issue https://github.com/flutter/flutter/issues/104802 ever + // is resolved on the VS side, we can allow these paths again + testUsingContext('Test bad path characters', () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final BuildWindowsCommand command = BuildWindowsCommand() + ..visualStudioOverride = fakeVisualStudio; + fileSystem.currentDirectory = fileSystem.directory("test_'path") + ..createSync(); + final String absPath = fileSystem.currentDirectory.absolute.path; + setUpMockCoreProjectFiles(); + + expect( + createTestCommandRunner(command).run(const ['windows', '--no-pub']), + throwsToolExit( + message: + 'Path $absPath contains invalid characters in "\'#!\$^&*=|,;<>?". ' + 'Please rename your directory so as to not include any of these characters ' + 'and retry.', + ), + ); + }, overrides: { + Platform: () => windowsPlatform, + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), + }); } class FakeVisualStudio extends Fake implements VisualStudio {