mkNugetSource: remove mono from build closure

A directory full of *.nupkg files is a valid nuget source. We do not need mono
and the Nuget command line tool to create this structure. This has two
advantages:

- Nuget is currently broken due to a kernel bug affecting mono (#229476).
Replacing the mkNugetSource implementation allows affected users on 6.1+
kernels compile .NET core packages again.
- It removes mono from the build closure of .NET core packages. .NET core
builds should not depend on .NET framework tools like mono.

There is no equivalent of the `nuget init` command in .NET core. The closest
command is `dotnet nuget push`, which just copies the *.nupkg files around
anyway, just like this PR does with `cp`.

`nuget init` used to extract the *.nuspec files from the nupkgs, this new
implementation doesn't. .NET core doesn't care, but it makes the license
extraction more difficult. What was previously done with find/grep/xml2 is now
a python script (extract-licenses-from-nupkgs.py).

+39 -9
+9 -9
pkgs/build-support/dotnet/make-nuget-source/default.nix
··· 1 - { dotnetPackages, lib, xml2, stdenvNoCC }: 1 + { lib, python3, stdenvNoCC }: 2 2 3 3 { name 4 4 , description ? "" ··· 10 10 inherit name; 11 11 12 12 meta.description = description; 13 - nativeBuildInputs = [ dotnetPackages.Nuget xml2 ]; 13 + nativeBuildInputs = [ python3 ]; 14 14 15 15 buildCommand = '' 16 - export HOME=$(mktemp -d) 17 16 mkdir -p $out/{lib,share} 18 17 19 - ${lib.concatMapStringsSep "\n" (dep: '' 20 - nuget init "${dep}" "$out/lib" 21 - '') deps} 18 + ( 19 + shopt -s nullglob 20 + for nupkg in ${lib.concatMapStringsSep " " (dep: "\"${dep}\"/*.nupkg") deps}; do 21 + cp --no-clobber "$nupkg" $out/lib 22 + done 23 + ) 22 24 23 25 # Generates a list of all licenses' spdx ids, if available. 24 26 # Note that this currently ignores any license provided in plain text (e.g. "LICENSE.txt") 25 - find "$out/lib" -name "*.nuspec" -exec sh -c \ 26 - "NUSPEC=\$(xml2 < {}) && echo "\$NUSPEC" | grep license/@type=expression | tr -s \ '\n' | grep "license=" | cut -d'=' -f2" \ 27 - \; | sort -u > $out/share/licenses 27 + python ${./extract-licenses-from-nupkgs.py} $out/lib > $out/share/licenses 28 28 ''; 29 29 } // { # We need data from `$out` for `meta`, so we have to use overrides as to not hit infinite recursion. 30 30 meta.licence = let
+30
pkgs/build-support/dotnet/make-nuget-source/extract-licenses-from-nupkgs.py
··· 1 + #!/usr/bin/env python3 2 + """ 3 + Opens each .nupkg file in a directory, and extracts the SPDX license identifiers 4 + from them if they exist. The SPDX license identifier is stored in the 5 + '<license type="expression">...</license>' tag in the .nuspec file. 6 + All found license identifiers will be printed to stdout. 7 + """ 8 + 9 + from glob import glob 10 + from pathlib import Path 11 + import sys 12 + import xml.etree.ElementTree as ET 13 + import zipfile 14 + 15 + all_licenses = set() 16 + 17 + if len(sys.argv) < 2: 18 + print(f"Usage: {sys.argv[0]} DIRECTORY") 19 + sys.exit(1) 20 + 21 + nupkg_dir = Path(sys.argv[1]) 22 + for nupkg_name in glob("*.nupkg", root_dir=nupkg_dir): 23 + with zipfile.ZipFile(nupkg_dir / nupkg_name) as nupkg: 24 + for nuspec_name in [name for name in nupkg.namelist() if name.endswith(".nuspec")]: 25 + with nupkg.open(nuspec_name) as nuspec_stream: 26 + nuspec = ET.parse(nuspec_stream) 27 + licenses = nuspec.findall(".//{*}license[@type='expression']") 28 + all_licenses.update([license.text for license in licenses]) 29 + 30 + print("\n".join(sorted(all_licenses)))