-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Fix some incorrect SpecialFolder entries for Unix #68610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b59cf19
a40e8fc
5feaed0
a17e734
62614de
332d842
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,31 +85,22 @@ private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) | |
| switch (folder) | ||
| { | ||
| case SpecialFolder.UserProfile: | ||
| case SpecialFolder.MyDocuments: // same value as Personal | ||
| return home; | ||
| case SpecialFolder.ApplicationData: | ||
| return GetXdgConfig(home); | ||
| case SpecialFolder.LocalApplicationData: | ||
| // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." | ||
| // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." | ||
| string? data = GetEnvironmentVariable("XDG_DATA_HOME"); | ||
| if (data is null || !data.StartsWith('/')) | ||
| { | ||
| data = Path.Combine(home, ".local", "share"); | ||
| } | ||
| return data; | ||
|
|
||
| case SpecialFolder.Desktop: | ||
| case SpecialFolder.DesktopDirectory: | ||
| return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); | ||
| case SpecialFolder.Templates: | ||
| return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); | ||
| case SpecialFolder.MyVideos: | ||
| return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); | ||
|
|
||
| #if TARGET_OSX | ||
| case SpecialFolder.ApplicationData: | ||
| case SpecialFolder.LocalApplicationData: | ||
| return Path.Combine(home, "Library", "Application Support"); | ||
| case SpecialFolder.MyDocuments: // same value as Personal | ||
| return Path.Combine(home, "Documents"); | ||
| case SpecialFolder.MyMusic: | ||
| return Path.Combine(home, "Music"); | ||
| case SpecialFolder.MyVideos: | ||
| return Path.Combine(home, "Movies"); | ||
| case SpecialFolder.MyPictures: | ||
| return Path.Combine(home, "Pictures"); | ||
| case SpecialFolder.Fonts: | ||
|
|
@@ -119,8 +110,23 @@ private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) | |
| case SpecialFolder.InternetCache: | ||
| return Path.Combine(home, "Library", "Caches"); | ||
| #else | ||
| case SpecialFolder.ApplicationData: | ||
| return GetXdgConfig(home); | ||
| case SpecialFolder.LocalApplicationData: | ||
| // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." | ||
| // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." | ||
| string? data = GetEnvironmentVariable("XDG_DATA_HOME"); | ||
| if (data is null || !data.StartsWith('/')) | ||
| { | ||
| data = Path.Combine(home, ".local", "share"); | ||
| } | ||
| return data; | ||
| case SpecialFolder.MyDocuments: // same value as Personal | ||
| return ReadXdgDirectory(home, "XDG_DOCUMENTS_DIR", "Documents"); | ||
|
||
| case SpecialFolder.MyMusic: | ||
| return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); | ||
| case SpecialFolder.MyVideos: | ||
| return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); | ||
| case SpecialFolder.MyPictures: | ||
| return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); | ||
| case SpecialFolder.Fonts: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -332,19 +332,21 @@ public void FailFast_ExceptionStackTrace_InnerException() | |
|
|
||
| [Fact] | ||
| [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] | ||
| public void GetFolderPath_Unix_PersonalExists() | ||
| public void GetFolderPath_Unix_UserProfileExists() | ||
| { | ||
| Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal))); | ||
| Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile))); | ||
| } | ||
|
|
||
| [Fact] | ||
| [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] // Tests OS-specific environment | ||
| public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() | ||
| public void GetFolderPath_Unix_PersonalIsDocumentsAndUserProfile() | ||
| { | ||
| if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst) | ||
| { | ||
| Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.Personal)); | ||
| Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); | ||
| Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"), | ||
| Environment.GetFolderPath(Environment.SpecialFolder.Personal, Environment.SpecialFolderOption.DoNotVerify)); | ||
| Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"), | ||
| Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify)); | ||
| } | ||
|
|
||
| Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); | ||
|
|
@@ -357,6 +359,7 @@ public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() | |
| [InlineData(Environment.SpecialFolder.Desktop)] | ||
| [InlineData(Environment.SpecialFolder.DesktopDirectory)] | ||
| [InlineData(Environment.SpecialFolder.Fonts)] | ||
| [InlineData(Environment.SpecialFolder.MyDocuments)] | ||
| [InlineData(Environment.SpecialFolder.MyMusic)] | ||
| [InlineData(Environment.SpecialFolder.MyPictures)] | ||
| [InlineData(Environment.SpecialFolder.MyVideos)] | ||
|
|
@@ -391,7 +394,7 @@ public void GetSystemDirectory() | |
| [Theory] | ||
| [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests OS-specific environment | ||
| [InlineData(Environment.SpecialFolder.UserProfile, Environment.SpecialFolderOption.None)] | ||
| [InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.None)] // MyDocuments == Personal | ||
| [InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify)] // MyDocuments == Personal | ||
|
||
| [InlineData(Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.None)] | ||
| [InlineData(Environment.SpecialFolder.CommonTemplates, Environment.SpecialFolderOption.DoNotVerify)] | ||
| [InlineData(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify)] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this ifdef be enabled for all Apple platforms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I sadly only have one Apple device which is running MacOS.
Don't the mobile platforms get the folder from a different place though? I thought they'd get it from here or is this mono specific?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not apply for iOS. Is that all other Apple platforms?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From quick skimming the RIDs, there's TVOS and MacCatalyst as well (and simulators for them). MacCatalyst is inheriting from iOS, tvOS is only inheriting from unix. I cannot however find much documentation regarding tvOS' file system right now. Does seem relatively locked down though, with apps not meant to write to local storage and mostly to the cloud instead.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, I have missed that this file is ifdefed out.
Is there a good reason for the default folder handling to differ between macOS and other Apple OSes? Should macOS be switched to just use https://github.com/dotnet/runtime/blob/main/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am not that familiar with the codebase, but my two cents are, that it probably would be better to put macOS into there as well, rename the file to
Environment.Apple, and put some macOS specific checks in there (for i.e.ApplicationData,Personaletc.).On another note, why does
Environment.iOShardcode the subdirectories, instead of invoking the respective NSLibrary paths?For
SpecialFolder.Desktopfor example,NSDocumentDirectory/Desktopis used instead ofNSDesktopDirectorywhich according to the Apple docs at least work on all Apple OS. This is probably a thing for a separate PR, but was curious nonetheless.(Also, updated link for Environment.iOS)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that if you're going to do breaking changes, do it right by using NSSearchPathDirectory values as much as possible, like it's done for iOS here:
runtime/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs
Lines 84 to 85 in 16cb35f
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can see, that'd require changing the method's return value fromNevermind, forgot thatstringtostring?(as theInterop.Sys.SearchPathmethod can return null), which would be yet another API break. Is that a change worth having?GetFolderPathCoreWithoutValidationis an internal method.