From ebfaa45c7d23374a7f3f596adea62ae1dd4e5845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:52:11 -0700 Subject: [PATCH] [Windows] Improve symlink ERROR_ACCESS_DENIED error message (#154030) Currently, if creating a symlink on Windows fails due to `ERROR_ACCESS_DENIED`, you'll get an error message like: ``` Error: ERROR_ACCESS_DENIED file system exception thrown while trying to create a symlink from source to dest ``` The `source` and `dest` paths are incorrect. This will help us debug: https://github.com/flutter/flutter/issues/153758 --- .../lib/src/flutter_plugins.dart | 4 +- .../test/general.shard/plugins_test.dart | 75 +++++++++++++++---- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index f11f0b86a8b..798f49d2238 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -993,8 +993,8 @@ void _createPlatformPluginSymlinks(Directory symlinkDirectory, List? pl e, platform: globals.platform, os: globals.os, - destination: 'dest', - source: 'source', + destination: link.path, + source: path, ); rethrow; } diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index f7f00d2f808..5f54564a6a7 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -1844,24 +1844,73 @@ The Flutter Preview device does not support the following plugins from your pubs ); }); - testWithoutContext('Symlink ERROR_ACCESS_DENIED failures show developers paths that were used', () async { - final Platform platform = FakePlatform(operatingSystem: 'windows'); - final FakeOperatingSystemUtils os = FakeOperatingSystemUtils('Microsoft Windows [Version 10.0.14972.1]'); + testUsingContext('Symlink ERROR_ACCESS_DENIED failures show developers paths that were used', () async { + final FakeFlutterProject flutterProject = FakeFlutterProject() + ..directory = globals.fs.currentDirectory.childDirectory('app'); + final Directory windowsManagedDirectory = flutterProject.directory + .childDirectory('windows') + .childDirectory('flutter'); + final FakeWindowsProject windowsProject = FakeWindowsProject() + ..managedDirectory = windowsManagedDirectory + ..pluginSymlinkDirectory = windowsManagedDirectory + .childDirectory('ephemeral') + .childDirectory('.plugin_symlinks') + ..exists = true; - const FileSystemException e = FileSystemException('', '', OSError('', 5)); + final File dependenciesFile = flutterProject.directory + .childFile('.flutter-plugins-dependencies'); + flutterProject + ..flutterPluginsDependenciesFile = dependenciesFile + ..windows = windowsProject; + + flutterProject.directory.childFile('.packages').createSync(recursive: true); + + const String dependenciesFileContents = r''' +{ + "plugins": { + "windows": [ + { + "name": "some_plugin", + "path": "C:\\some_plugin" + } + ] + } +} +'''; + dependenciesFile.writeAsStringSync(dependenciesFileContents); + + const String expectedMessage = + 'ERROR_ACCESS_DENIED file system exception thrown while trying to ' + r'create a symlink from C:\some_plugin to ' + r'C:\app\windows\flutter\ephemeral\.plugin_symlinks\some_plugin'; expect( - () => handleSymlinkException( - e, - platform: platform, - os: os, - source: pubCachePath, - destination: ephemeralPackagePath, - ), - throwsToolExit( - message: 'ERROR_ACCESS_DENIED file system exception thrown while trying to create a symlink from $pubCachePath to $ephemeralPackagePath', + () => createPluginSymlinks( + flutterProject, + featureFlagsOverride: TestFeatureFlags(isWindowsEnabled: true), ), + throwsToolExit(message: expectedMessage), ); + }, overrides: { + FileSystem: () { + final FileExceptionHandler handle = FileExceptionHandler(); + final ErrorHandlingFileSystem fileSystem = ErrorHandlingFileSystem( + platform: FakePlatform(), + delegate: MemoryFileSystem.test( + style: FileSystemStyle.windows, + opHandle: handle.opHandle, + ), + ); + const String pluginSymlinkPath = r'C:\app\windows\flutter\ephemeral\.plugin_symlinks\some_plugin'; + handle.addError( + fileSystem.link(pluginSymlinkPath), + FileSystemOp.create, + const FileSystemException('', '', OSError('', 5)), + ); + return fileSystem; + }, + Platform: () => FakePlatform(operatingSystem: 'windows'), + ProcessManager: () => FakeProcessManager.empty(), }); testWithoutContext('Symlink failures instruct developers to run as administrator on older versions of Windows', () async {