ScoopInstaller / Main

📦 The default bucket for Scoop.
https://scoop.sh
The Unlicense
1.59k stars 964 forks source link

Dotnet-SDK Improvements #874

Open JustinGrote opened 4 years ago

JustinGrote commented 4 years ago
  1. Should set DOTNET_ROOT user environment variable for the user to the "current" path. Had several apps break because they couldn't find it, especially ones that use hostfxr.dll
  2. Previous versions should have an NTFS junction in the "dotnet/sdk" subfolder so they can be recognized and used, for instance if you need to develop on 2.1 and 3.1 applications simultaneously. This can be done as a post-install step.
Ash258 commented 4 years ago

https://github.com/ScoopInstaller/Main/blob/71df3eb17cd0de34eef4066d546a5ea8e55974bf/bucket/dotnet-sdk.json#L21-L24

JustinGrote commented 4 years ago

@Ash258 My apologies, I didn't see either get set when I installed and had a bunch of stuff not work as a result. Let me do a full refresh and check back.

JustinGrote commented 4 years ago

https://github.com/ScoopInstaller/Main/blob/71df3eb17cd0de34eef4066d546a5ea8e55974bf/bucket/dotnet-sdk.json#L23

I see this points it to the SDKs folder but it doesn't do anything to reference any additional SDKs installed on the system. Say if I installed 2.1 previously, it should add an NTFS junction in here for the 2.1 which is still installed in a previous versions folder.

Is that too outside the scope of the installer and should be done manually or with a custom post-script? Doesn't seem too unreasonable to me.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

kevin-stuart commented 2 years ago

Can this issue be reopened or should one file a new one?

The thing is, this issue is absolutely correct and is important now that .NET 6 has been released. Even before, updates have been problematic because of MSBuildSDKsPath. If you updated even the minor version of dotnet, any open consoles will not work because the MSBuildSDKsPath variable would need to be updated to match the updated dotnet SDK version since the shim refers to a different version afterwards and the msbuild version would not match anymore.

It seems that for .NET core, the sdk is meant to be used with multiple versions to be installed simulataneously side-by-side. There now even is a dotnet sdk check command. An elegant solution would be to do links/junctions so that dotnet-sdk/current contains links to all appropriate directories in the specific version directories. For instance, dotnet-sdk/current/sdk and dotnet-sdk/current/template should link to the subdirectories of the other dotnet versions.

rashil2000 commented 2 years ago

How do you propose the junctions should be made? Can you write a script that the manifest can utilize? We will put it in the https://github.com/ScoopInstaller/Main/tree/master/scripts folder.

kevin-stuart commented 2 years ago

I looked into how it would probably be need to be done. I was thinking of writing a script for myself, but was looking if the scoop community was already aware of this and trying to solve this.

What I figured out:

Basically if you install a verison such as for example 6.0.100, you will get this structure for the 6.0.100 or current directory, as they are the same:

$env:USERPROFILE\scoop\apps\dotnet-sdk\current\sdk-manifests\6.0.100 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\sdk\6.0.100 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\host\fxr\6.0.0 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\packs*\6.0.0 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\shared*\6.0.0 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\templates\6.0.0

If you do have another version, for example 5.0.400, you would need to link the directories of the other SDKS to these locations:

$env:USERPROFILE\scoop\apps\dotnet-sdk\current\sdk\5.0.400 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\host\fxr\5.0.9 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\packs*\5.0.9 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\shared*\5.0.9 $env:USERPROFILE\scoop\apps\dotnet-sdk\current\templates\5.0.9

The * stands for multiple subdirectories. You would need to traverse them and link the directories.

Basically, MS uses DOTNET_ROOT to install all installed .NET core SDKs side by side, so if you call dotnet in some project and have all versions installed, the correct version for a project can be used among the installed versions, since you need a .NET 5 SDK if the project targets this level, the .NET 6 version is not enough. This model does not fit very well with the isolated model of scoop. So linking the versions into the latest scoop version is the best idea I have.

I don't know if I have enough time to write the script soon and was hoping that someone else already had a fix prepared. But I might try. The script would need to be a powershell script, a .reg as in your link will not be enough. I don't know how it would be embedded in the install process, I think I saw a postinstall in some manifest.

rashil2000 commented 2 years ago

The script would need to be a powershell script, a .reg as in your link will not be enough. I don't know how it would be embedded in the install process, I think I saw a postinstall in some manifest.

That's alright. It can be any script, I was just pointing to an example. Take a look here, we have ps1 scripts too - https://github.com/ScoopInstaller/Extras/tree/master/scripts.

It will be invoked in the post_install.

kevin-stuart commented 2 years ago

I have draft of how to do it:

function link($src, $tgt) {
    "$src -> $tgt"  # replace this with below to perform for real
    # New-Item -Path $tgt -ItemType Junction -Value $src
}

function step($tgt, $src, $common, $fw) {
    if (-not (Test-Path "$src/$common")) { return }
    gci "$src/$common/$fw" | % {
        $p0 = [System.IO.Path]::GetRelativePath("$src/$common", $_)
        $a1 = "$_" -replace "[/\\]", [IO.Path]::DirectorySeparatorChar
        $a2 = "$tgt/$common/$p0" -replace
            "[/\\]", [IO.Path]::DirectorySeparatorChar
        ,($a1, $a2)
    }
}

function main() {
    $base = "$env:USERPROFILE/scoop/apps/dotnet-sdk"
    $versions = (gci $base | ? {!$_.LinkType} | % {$_.BaseName})
    $tgt = $versions[-1]
    $srcs = $versions[0..($versions.Length - 2)]
    if ($versions.Length -le 1) { break }
    $srcs | % {
        step "$base/$tgt" "$base/$_" "sdk-manifests" "*"
        step "$base/$tgt" "$base/$_" "sdk" "*"
        step "$base/$tgt" "$base/$_" "templates" "*"
        step "$base/$tgt" "$base/$_" "host/fxr" "*"
        step "$base/$tgt" "$base/$_" "packs" "*/*"
        step "$base/$tgt" "$base/$_" "shared" "*/*"
    } | % {link $_[0] $_[1]}
}

main
Sei-lus commented 2 years ago

So this was forgotten.

kevin-stuart commented 2 years ago

Not really forgotten, by me at least. We really need multiple versions as reported as well so we can install them just like e.g. Java.

If a project is set to use mulitple frameworks, Scoop can't handle this as all. For example for <TargetFrameworks>net5.0;net6.0</TargetFrameworks> we need 5 and 6 at the same time, but right now we can only do this if we do not remove older versions so we can link them as I illustrated.

kevin-stuart commented 2 years ago

I see that the version bucket now contains this, but someone with expertise needs to wrap up the ideas from my script outline in some smart manner. Maybe the a special manifest in versions that links all SDKs from the versions bucket?

Sei-lus commented 2 years ago

@kevin-stuart I would like for it to be something along these lines: Main package of "dotnet-sdk" would be the dominant version and contain latest non preview version. Main package of dotnet would look for "versions" upon update or install, or all version would install to dotnet sdk folder. Dotnet-sdk would have links to the frameworks at least, hopefully also SDKs. So installing dotnet5-sdk would do mirror itself to dotnet-sdk.

Right now I had installed dotnet-sdk, dotnet5-sdk and dotnet6-sdk (because I'm looking forward to dotnet-sdk using dotnet7.) But decided it wasn't working as it should. So used winget to get the frameworks and sdks instead. I really prefer scoop over winget but I spent hours trying to make it work with scoop to no avail.

Sei-lus commented 2 years ago

Actually, why does \Program Files\dotnet files show using scoop dotnet --info, while the scoop ones only show the ones in the folder of the dotnet.exe you are using?

kevin-stuart commented 2 years ago

The ones in "Program Files" are installed globally with admin right, they seem to be registered globally and are therefore found. The ones via scoop are only found in relative paths.

Jestar342 commented 2 years ago

I'm experiencing what I believe to be a related issue, but may not be (I'm not so well informed on dotnet runtimes, so apologies if this is unrelated.)

When an app (such as PowerToys, using the powertoys-np manifest in nonportable bucket) installs a dotnet runtime as a dependency, calling dotnet from the terminal will now invoke the globally installed dotnet from program files, and most importantly, the SDKs from scoop installed versions will not show in the list.

❯ dotnet --info

Host (useful for support):
  Version: 5.0.14
  Commit:  d5b56c6327

.NET SDKs installed:
  No SDKs were found.

.NET runtimes installed:
  Microsoft.NETCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

~
❯

but when explicitly calling the scoop install, it will list the sdk and the globally installed runtimes.

❯ ~\scoop\shims\dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.200
 Commit:    4c30de7899

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19043
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Users\<user>\scoop\apps\dotnet-sdk\current\sdk\6.0.200\

Host (useful for support):
  Version: 6.0.2
  Commit:  839cdfb0ec

.NET SDKs installed:
  6.0.200 [C:\Users\<user>\scoop\apps\dotnet-sdk\current\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.2 [C:\Users\<user>\scoop\apps\dotnet-sdk\current\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.2 [C:\Users\<user>\scoop\apps\dotnet-sdk\current\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.2 [C:\Users\<user>\scoop\apps\dotnet-sdk\current\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

~
❯

This is causing build/dev tools to use the (runtime only in this case) installation of dotnet (and failing) instead of the scoop installed dotnet SDK.

rashil2000 commented 2 years ago

The simple fix would be removing C:\Program Files\dotnet from System PATH. System PATH has higher priority than User PATH so it will always override a Scoop installation.

kevin-stuart commented 2 years ago

There is one more ugly problem with scoop installs of dotnet-sdk and also updates: The MSBuildSDKsPath environment variable. It always contains specific version number that can change with updtes. It is also hard to figure out. This should probably also be linked to a 2nd current in the path.

Sei-lus commented 2 years ago

I'll love the script when it is working. For now, winget is the way to go for me... for runtimes at least. Winget doesn't over sdk 5 for example.

chawyehsu commented 2 years ago

The MSBuildSDKsPath env is actually the key causing the problem you guys talked above according to my investigation. It was introduced in #479 (I'm surprised that I approved this PR..) as a fix for omnisharp-vscode. However, despite it works it's a bad workaround instead of a fix. The SDK 'Microsoft.NET.Sdk' specified could not be found issue has been reported to omnisharp-vscode for so many times, and it's platform-neutral because it's been reported from all three major OSes users.

In fact, the dotnet CLI works as expected when the root folder is added to PATH, and you can also run dotnet build task, which is created by omnisharp-vscode, from VSCode without any issue, except for omnisharp's functionalities. See https://github.com/OmniSharp/omnisharp-vscode/issues/2821#issuecomment-529623140 and you know why MSBuildSDKsPath is not a fix.

P.S. Neither DOTNET_ROOT nor MSBuildSDKsPath will be set when you install dotnet sdk with the dotnet sdk Windows installer.

xiaoxstz commented 8 months ago

In short, scoop cannot make all versions available without switching with the command scoop reset app_name ?