NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.39k stars 13.62k forks source link

.NET workloads fail to install #226107

Open JamieMagee opened 1 year ago

JamieMagee commented 1 year ago

Describe the bug

Since .NET 5.0, .NET has shipped as a 'slim' SDK with support for optional workloads^1. Optional workloads are expected to be installed by the user.

Steps To Reproduce

Steps to reproduce the behavior:

  1. nix-shell -p dotnet-sdk_6
  2. dotnet workload install android
  3. Error
Unhandled exception: System.IO.IOException: Read-only file system : '/nix/store/r04bnvsq19hpds9i7cdrlzcn2cbrs701-dotnet-sdk-6.0.407/metadata'
   at System.IO.FileSystem.CreateDirectory(String fullPath)
   at System.IO.Directory.CreateDirectory(String path)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallerFactory.CanWriteToDotnetRoot(String dotnetDir)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallerFactory.GetWorkloadInstaller(IReporter reporter, SdkFeatureBand sdkFeatureBand, IWorkloadResolver workloadResolver, VerbosityOptions verbosity, String userProfileDir, Boolean verifySignatures, INuGetPackageDownloader nugetPackageDownloader, String dotnetDir, String tempDirPath, PackageSourceLocation packageSourceLocation, RestoreActionConfig restoreActionConfig, Boolean elevationRequired)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallCommand..ctor(ParseResult parseResult, IReporter reporter, IWorkloadResolver workloadResolver, IInstaller workloadInstaller, INuGetPackageDownloader nugetPackageDownloader, IWorkloadManifestUpdater workloadManifestUpdater, String dotnetDir, String userProfileDir, String tempDirPath, String version, IReadOnlyCollection`1 workloadIds, String installedFeatureBand)
   at Microsoft.DotNet.Cli.WorkloadInstallCommandParser.<>c.<ConstructCommand>b__6_0(ParseResult parseResult)
   at Microsoft.DotNet.Cli.ParseResultCommandHandler.Invoke(InvocationContext context)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.CommandLineBuilderExtensions.<>c__DisplayClass12_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__18_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.CommandLineBuilderExtensions.<>c__DisplayClass16_0.<<UseParseDirective>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.CommandLineBuilderExtensions.<>c__DisplayClass8_0.<<UseExceptionHandler>b__0>d.MoveNext()

Expected behavior

Workloads to be enabled using nix configuration

Screenshots

N/A

Additional context

With the following .NET SDKs installed

6.0.407 [/nix/store/85fshpgixw0r5a8ar901z9i4xqs6izwg-dotnet-core-combined/sdk]
7.0.202 [/nix/store/85fshpgixw0r5a8ar901z9i4xqs6izwg-dotnet-core-combined/sdk]
8.0.100-preview.2.23157.25 [/nix/store/85fshpgixw0r5a8ar901z9i4xqs6izwg-dotnet-core-combined/sdk]

The following workloads are available

$ dotnet workload search

Workload ID                 Description                                         
--------------------------------------------------------------------------------
android                     .NET SDK Workload for building Android applications.
macos                       .NET SDK Workload for building macOS applications.  
maui-android                .NET MAUI SDK for Android                           
maui-tizen                  .NET MAUI SDK for Tizen                             
maui-windows                .NET MAUI SDK for Windows                           
runtimes-windows            workloads/runtimes-windows/description              
runtimes-windows-net6       workloads/runtimes-windows-net6/description         
runtimes-windows-net7       workloads/runtimes-windows-net7/description         
wasi-experimental           workloads/wasi-experimental/description             
wasm-experimental           workloads/wasm-experimental/description             
wasm-experimental-net7      workloads/wasm-experimental-net7/description        
wasm-tools                  .NET WebAssembly build tools                        
wasm-tools-net6             .NET WebAssembly build tools                        
wasm-tools-net7             workloads/wasm-tools-net7/description

Notify maintainers

@kuznero @mdarocha

Metadata

 - system: `"x86_64-linux"`
 - host os: `Linux 6.2.10, NixOS, 23.05 (Stoat), 23.05.20230412.fe2ecaf`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.14.1`
 - channels(root): `"nixos"`
 - nixpkgs: `/nix/store/qyyw6dd6lqlhz3cqap31d071cbyh34bf-source`
JamieMagee commented 1 year ago

A mapping of .NET workload to NuGet packages required is here:

mdarocha commented 1 year ago

Related: https://github.com/NixOS/nixpkgs/pull/181636

JamieMagee commented 1 year ago

@mdarocha thanks!

@Smaug123 it looks like you had more success with dotnet workloads in https://github.com/Smaug123/nix-maui. Would you be interested in upstreaming your work to nixpkgs?

Smaug123 commented 1 year ago

I'm afraid this isn't something I'd be happy to maintain - it mostly works but is definitely suboptimal and would probably be a decent amount of work to upstream.

mdarocha commented 1 year ago

If I'll find the time, I'll attempt to expand on @Smaug123's work

adamreed90 commented 6 months ago

Since the dotnet workload installer now supports installing to a user directory, could it be possible to simply relocate the dotnet-sdk nixpkg to user space?

Smaug123 commented 6 months ago

A possible spanner in the works: PublishAot pulls down some binaries from NuGet, and therefore fails out of the box on NixOS because the AOT compiler can't find the linker (or something like that, it's been a while). So there's always going to have to be some amount of Nix wrangling somewhere.

srs-adamr commented 6 months ago

A possible spanner in the works: PublishAot pulls down some binaries from NuGet, and therefore fails out of the box on NixOS because the AOT compiler can't find the linker (or something like that, it's been a while). So there's always going to have to be some amount of Nix wrangling somewhere.

This makes me so very sad, I only recently started using NixOS and I am a .NET developer by trade, I want to daily drive this so badly :(

anpin commented 6 months ago

even if workloads are installed in user space they are still failing to build https://github.com/dotnet/sdk/issues/37706

float3 commented 4 months ago

does no solution to this exist?

anpin commented 3 months ago

@float3 take a look at workaround here, seems to work for some

devurandom commented 1 month ago

Copied from: https://github.com/NixOS/nixpkgs/issues/325667

Describe the bug

It is currently impossible to install .NET workloads on NixOS:

❯ dotnet workload install maui
Unhandled exception: System.IO.IOException: Read-only file system : '/nix/store/as1j1inzdjdaca6gdcfdr2bdsppgr3px-dotnet-sdk-8.0.300/metadata'
   at System.IO.FileSystem.CreateDirectory(String fullPath, UnixFileMode unixCreateMode)
   at System.IO.Directory.CreateDirectory(String path)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallerFactory.CanWriteToDotnetRoot(String dotnetDir)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallerFactory.GetWorkloadInstaller(IReporter reporter, SdkFeatureBand sdkFeatureBand, IWorkloadResolver workloadResolver, VerbosityOptions verbosity, String userProfileDir, Boolean verifySignatures, INuGetPackageDownloader nugetPackageDownloader, String dotnetDir, String tempDirPath, PackageSourceLocation packageSourceLocation, RestoreActionConfig restoreActionConfig, Boolean elevationRequired, Boolean shouldLog)
   at Microsoft.DotNet.Workloads.Workload.Install.WorkloadInstallCommand..ctor(ParseResult parseResult, IReporter reporter, IWorkloadResolverFactory workloadResolverFactory, IInstaller workloadInstaller, INuGetPackageDownloader nugetPackageDownloader, IWorkloadManifestUpdater workloadManifestUpdater, String tempDirPath, IReadOnlyCollection`1 workloadIds)
   at Microsoft.DotNet.Cli.WorkloadInstallCommandParser.<>c.<ConstructCommand>b__6_0(ParseResult parseResult)
   at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult)
   at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)

Steps To Reproduce

Steps to reproduce the behavior:

  1. Install the .NET Core 8 SDK: environment.systemPackages = [ pkgs.dotnet-sdk_8 ];
  2. Try to install a workload: dotnet workload install maui
  3. Observe error

Expected behavior

dotnet workload install maui should install the workload in a user-writeable location.

Additional context

According to https://github.com/dotnet/sdk/pull/18823 this can be fixed by writing a file <DOTNET_ROOT>/metadata/workloads/<sdkfeatureband>/userlocal. https://discourse.nixos.org/t/dotnet-maui-workload/20370 contains shell code examples how to do that.

Notify maintainers

@kuznero, @mdarocha

Metadata

❯ nix-shell -p nix-info --run "nix-info -m"
 - system: `"x86_64-linux"`
 - host os: `Linux 6.9.7, NixOS, 24.05 (Uakari), 24.05.20240702.706eef5`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.18.4`
 - channels(root): `"nixos"`
 - nixpkgs: `/nix/store/0z4i8wyg3ymm7kkb1gk2wyh08x230c6z-source`

Add a :+1: reaction to issues you find important.

nixos-discourse commented 1 month ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/dotnet-maui-workload/20370/21

EmVee381 commented 1 month ago

@float3 take a look at workaround here, seems to work for some

thanks, it helped me with android workflow

anpin commented 1 month ago

@EmVee381 have you found a workaround? Could you please share? Safely I never got it to work on my nixos machine

EmVee381 commented 1 month ago

@EmVee381 have you found a workaround? Could you please share? Safely I never got it to work on my nixos machine

i use devenv, but you can use it similar way

is it clear? it is just copy pasted from from your link :) it works for me very well, you just define overrieded package in between "let" block then use it as package in your derivation or shell.nix or anything and set environment variable DOTNET_ROOT edited: pkgs-stable is not needed it is another input for my devenv testing purposes :)

{ pkgs, lib, config, inputs, ... }:

let
  pkgs-stable = import inputs.nixpkgs-stable { system = pkgs.stdenv.system; };
  dotnet-combined = (with pkgs.dotnetCorePackages; combinePackages [
    sdk_8_0
  ]).overrideAttrs (finalAttrs: previousAttrs: {
    # This is needed to install workload in $HOME
    # https://discourse.nixos.org/t/dotnet-maui-workload/20370/2
    postBuild = (previousAttrs.postBuild or '''') + ''
       for i in $out/sdk/*
       do
         i=$(basename $i)
         length=$(printf "%s" "$i" | wc -c)
         substring=$(printf "%s" "$i" | cut -c 1-$(expr $length - 2))
         i="$substring""00"
         mkdir -p $out/metadata/workloads/''${i/-*}
         touch $out/metadata/workloads/''${i/-*}/userlocal
      done
    '';
  });
in
rec
{
  env.GREET = "avalonia";
  env.DOTNET_ROOT = "${dotnet-combined}";
  languages.dotnet.enable = true;
  languages.dotnet.package = dotnet-combined;
  packages = [
    pkgs.git
    pkgs.omnisharp-roslyn
  ];

}