NuGet / Home

Repo for NuGet Client issues
Other
1.5k stars 253 forks source link

[Bug]: dotnet.exe errors when using any cache folder. #11863

Closed CCnut closed 2 years ago

CCnut commented 2 years ago

NuGet Product Used

dotnet.exe

Product Version

Version: 5.0.17 Commit: 6a98414363

Worked before?

No response

Impact

It bothers me. A fix would be nice

Repro Steps & Context

Build a windows app using the Drone CI. I checked the environment. The pipeline does not have LOCALAPPDATA.

Reproduce step:

Verbose Logs

---> System.ArgumentNullException: Value cannot be null. (Parameter 'path1')
                        at System.IO.Path.Combine(String path1, String path2, String path3)
                        at NuGet.Common.NuGetEnvironment.GetFolderPath(NuGetFolderPath folder)
                        at NuGet.Configuration.SettingsUtility.GetHttpCacheFolder()
                        at NuGet.Protocol.HttpSource.GetAsync[T](HttpSourceCachedRequest request, Func`2 processAsync, ILogger log, CancellationToken token)
                        at NuGet.Protocol.ServiceIndexResourceV3Provider.GetServiceIndexResourceV3(SourceRepository source, DateTime utcNow, ILogger log, CancellationToken token)
nkolev92 commented 2 years ago

Hey @CCnut

As you probably have guessed, this isn't a super common occurence, NuGet relies on Environment.SpecialFolder.LocalApplicationData being a valid and writable path on the machine it's running on.

Are you able to set LocalAppData on that machine?

nkolev92 commented 2 years ago

Note that this is the behavior in all NuGet tooling, VS, dotnet.exe and nuget.exe

zivkan commented 2 years ago

team triage meeting: We expect common Windows environment variables, and APIs to return without throwing. We recently had another customer who experienced a similar issue when using NuGet.Protocol in an IIS app: https://github.com/NuGet/Home/issues/11762 In their case, IIS was not configured correctly. So, our suggestion is to ensure that the machine is configured according to best practises, but the NuGet team are not experts on machine configuration.

CCnut commented 2 years ago

I checked the diagnostic log. the MSBuild can read LOCALAPPDATA correct, but the NuGet can not. Note: Drone CI will changed USERPROFILE path.

logs_windows_app_37_1_3.log

zivkan commented 2 years ago

SettingsUtility.GetHttpCacheFolder calls NuGetEnvironment.GetFolderPath(NuGetFolderPath.HttpCacheDirectory): https://github.com/NuGet/NuGet.Client/blob/cd24c74285728884cab24e6ba027d75d418c0479/src/NuGet.Core/NuGet.Configuration/Utility/SettingsUtility.cs#L349

GetNuGetEnvironment.GetFolderPath(NuGetFolderPath.HttpCacheDirectory) calls GetFolderPath(SpecialFolder.LocalApplicationData): https://github.com/NuGet/NuGet.Client/blob/cd24c74285728884cab24e6ba027d75d418c0479/src/NuGet.Core/NuGet.Common/PathUtil/NuGetEnvironment.cs#L59-L61

dotnet cli (.NET (core))

GetFolderPath(SpecialFolder.LocalApplicationData) calls Environment.GetEnvironmentVariable("LOCALAPPDATA"): https://github.com/NuGet/NuGet.Client/blob/cd24c74285728884cab24e6ba027d75d418c0479/src/NuGet.Core/NuGet.Common/PathUtil/NuGetEnvironment.cs#L152

msbuild.exe (.NET Framework)

GetFolderPath(SpecialFolder.LocalApplicationData) calls Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData): https://github.com/NuGet/NuGet.Client/blob/cd24c74285728884cab24e6ba027d75d418c0479/src/NuGet.Core/NuGet.Common/PathUtil/NuGetEnvironment.cs#L218

Envionrment.GetFolderPath calls InternalGetFolderPath: https://referencesource.microsoft.com/#mscorlib/system/environment.cs,1450

InternalGetFolderPath P/Invokes the win32 API SHGetFolderPath: https://referencesource.microsoft.com/#mscorlib/system/environment.cs,1506

I don't know how SHGetFolder is implemented, but this certainly was the right thing to do 11 years ago when NuGet was first written (vs looking for an environment variable), as it allowed Mono to implement Environment.GetFolderPath in a way that made sense on Linux and Mac, so NuGet would work on those platforms without changes. This API didn't exist, however, in .NET Core 1.0, hence why NuGet checks for the platform, and uses the environment variable on windows, but this lack of Environment.GetFolderPath has led to a bug on Linux and mac because nuget.exe on mono, and the dotnet cli, now use different paths.

So, if your solution can be built with the .NET cli, then using dotnet restore instaed of msbuild -t:restore might be a workaround. Otherwise, I'm afraid I don't know how to resolve the issue. In my opinion, NuGet is making the right choice in which APIs it uses (except that NuGet didn't switch to Environment.GetFolderPath once .NET Standard introduced the API). I'm not a Windows expert, so I don't know how Windows Services should be configured to work (or if Drone CI is even installed as a WIndows Service).

CCnut commented 2 years ago

In the ReactOS source code, SHGetFolderPathW for the current user is read from HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders. All paths are based on USERPROFILE.

That is why MSBuild can read, when LOCALAPPDATA is null. regedit.exe

shai-bennathan commented 8 months ago

Thanks to this issue's existence I was able to solve my issue of running UTs which call "dotnet nuget ..." on windows in a python-tox isolated environment (which doesn't carry over the environment variables). What would have helped much more (and saved a lot of time) would have been a better error (e.g. 'Required LOCALAPPCONFIG environment variable is not set')...

If anyone found this issue by searching for 'tox' and the error, the solution is to add this section to your tox.ini (used in windows):

[testenv]
passenv =
    LOCALAPPDATA