at master 9.3 kB view raw
1{ 2 stdenv, 3 stdenvNoCC, 4 lib, 5 writeText, 6 testers, 7 runCommand, 8 runCommandWith, 9 darwin, 10 expect, 11 curl, 12 installShellFiles, 13 callPackage, 14 zlib, 15 swiftPackages, 16 icu, 17 lndir, 18 replaceVars, 19 nugetPackageHook, 20 xmlstarlet, 21 pkgs, 22 recurseIntoAttrs, 23}: 24type: unwrapped: 25stdenvNoCC.mkDerivation (finalAttrs: { 26 pname = "${unwrapped.pname}-wrapped"; 27 inherit (unwrapped) version; 28 29 meta = { 30 description = "${unwrapped.meta.description or "dotnet"} (wrapper)"; 31 mainProgram = "dotnet"; 32 inherit (unwrapped.meta) 33 homepage 34 license 35 maintainers 36 platforms 37 ; 38 }; 39 40 src = unwrapped; 41 dontUnpack = true; 42 43 setupHooks = [ 44 ./dotnet-setup-hook.sh 45 ] 46 ++ lib.optional (type == "sdk") ( 47 replaceVars ./dotnet-sdk-setup-hook.sh { 48 inherit lndir xmlstarlet; 49 } 50 ); 51 52 propagatedSandboxProfile = toString unwrapped.__propagatedSandboxProfile; 53 54 propagatedBuildInputs = lib.optional (type == "sdk") nugetPackageHook; 55 56 nativeBuildInputs = [ installShellFiles ]; 57 58 outputs = [ "out" ] ++ lib.optional (unwrapped ? man) "man"; 59 60 installPhase = '' 61 runHook preInstall 62 mkdir -p "$out"/bin "$out"/share 63 ln -s "$src"/bin/* "$out"/bin 64 ln -s "$src"/share/dotnet "$out"/share 65 runHook postInstall 66 ''; 67 68 postInstall = '' 69 # completions snippets taken from https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete 70 installShellCompletion --cmd dotnet \ 71 --bash ${./completions/dotnet.bash} \ 72 --zsh ${./completions/dotnet.zsh} \ 73 --fish ${./completions/dotnet.fish} 74 ''; 75 76 doInstallCheck = true; 77 78 installCheckPhase = '' 79 runHook preInstallCheck 80 HOME=$(mktemp -d) $out/bin/dotnet --info 81 runHook postInstallCheck 82 ''; 83 84 postFixup = lib.optionalString (unwrapped ? man) '' 85 ln -s ${unwrapped.man} "$man" 86 ''; 87 88 passthru = unwrapped.passthru // { 89 inherit unwrapped; 90 tests = 91 let 92 mkDotnetTest = 93 { 94 name, 95 stdenv ? stdenvNoCC, 96 template, 97 lang ? null, 98 usePackageSource ? false, 99 build, 100 buildInputs ? [ ], 101 runtime ? finalAttrs.finalPackage.runtime, 102 runInputs ? [ ], 103 run ? null, 104 runAllowNetworking ? false, 105 }: 106 let 107 sdk = finalAttrs.finalPackage; 108 built = stdenv.mkDerivation { 109 name = "${sdk.name}-test-${name}"; 110 buildInputs = [ sdk ] ++ buildInputs ++ lib.optional (usePackageSource) sdk.packages; 111 # make sure ICU works in a sandbox 112 propagatedSandboxProfile = toString sdk.__propagatedSandboxProfile; 113 unpackPhase = 114 let 115 unpackArgs = [ 116 template 117 ] 118 ++ lib.optionals (lang != null) [ 119 "-lang" 120 lang 121 ]; 122 in 123 '' 124 mkdir test 125 cd test 126 dotnet new ${lib.escapeShellArgs unpackArgs} -o . --no-restore 127 ''; 128 buildPhase = build; 129 dontPatchELF = true; 130 }; 131 in 132 # older SDKs don't include an embedded FSharp.Core package 133 if lang == "F#" && lib.versionOlder sdk.version "6.0.400" then 134 null 135 else if run == null then 136 built 137 else 138 runCommand "${built.name}-run" 139 ( 140 { 141 src = built; 142 nativeBuildInputs = [ built ] ++ runInputs; 143 passthru = { 144 inherit built; 145 }; 146 } 147 // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && runAllowNetworking) { 148 sandboxProfile = '' 149 (allow network-inbound (local ip)) 150 (allow mach-lookup (global-name "com.apple.FSEvents")) 151 ''; 152 __darwinAllowLocalNetworking = true; 153 } 154 ) 155 ( 156 lib.optionalString (runtime != null) '' 157 export DOTNET_ROOT=${runtime}/share/dotnet 158 '' 159 + run 160 ); 161 162 mkConsoleTests = 163 lang: suffix: output: 164 let 165 # Setting LANG to something other than 'C' forces the runtime to search 166 # for ICU, which will be required in most user environments. 167 checkConsoleOutput = command: '' 168 output="$(LANG=C.UTF-8 ${command})" 169 [[ "$output" =~ ${output} ]] && touch "$out" 170 ''; 171 172 mkConsoleTest = 173 { name, ... }@args: 174 mkDotnetTest ( 175 args 176 // { 177 name = "console-${name}-${suffix}"; 178 template = "console"; 179 inherit lang; 180 } 181 ); 182 in 183 lib.recurseIntoAttrs { 184 run = mkConsoleTest { 185 name = "run"; 186 build = checkConsoleOutput "dotnet run"; 187 }; 188 189 publish = mkConsoleTest { 190 name = "publish"; 191 build = "dotnet publish -o $out/bin"; 192 run = checkConsoleOutput "$src/bin/test"; 193 }; 194 195 self-contained = mkConsoleTest { 196 name = "self-contained"; 197 usePackageSource = true; 198 build = "dotnet publish --use-current-runtime --sc -o $out"; 199 runtime = null; 200 run = checkConsoleOutput "$src/test"; 201 }; 202 203 single-file = mkConsoleTest { 204 name = "single-file"; 205 usePackageSource = true; 206 build = "dotnet publish --use-current-runtime -p:PublishSingleFile=true -o $out/bin"; 207 runtime = null; 208 run = checkConsoleOutput "$src/bin/test"; 209 }; 210 211 ready-to-run = mkConsoleTest { 212 name = "ready-to-run"; 213 usePackageSource = true; 214 build = "dotnet publish --use-current-runtime -p:PublishReadyToRun=true -o $out/bin"; 215 run = checkConsoleOutput "$src/bin/test"; 216 }; 217 } 218 // lib.optionalAttrs finalAttrs.finalPackage.hasILCompiler { 219 aot = mkConsoleTest { 220 name = "aot"; 221 stdenv = if stdenv.hostPlatform.isDarwin then swiftPackages.stdenv else stdenv; 222 usePackageSource = true; 223 buildInputs = [ 224 zlib 225 ] 226 ++ lib.optional stdenv.hostPlatform.isDarwin [ 227 swiftPackages.swift 228 darwin.ICU 229 ]; 230 build = '' 231 dotnet restore -p:PublishAot=true 232 dotnet publish -p:PublishAot=true -o $out/bin 233 ''; 234 runtime = null; 235 run = checkConsoleOutput "$src/bin/test"; 236 }; 237 }; 238 239 mkWebTest = 240 lang: suffix: 241 mkDotnetTest { 242 name = "web-${suffix}"; 243 template = "web"; 244 inherit lang; 245 build = "dotnet publish -o $out/bin"; 246 runtime = finalAttrs.finalPackage.aspnetcore; 247 runInputs = [ 248 expect 249 curl 250 ]; 251 run = '' 252 expect <<"EOF" 253 set status 1 254 spawn $env(src)/bin/test 255 proc abort { } { exit 2 } 256 expect_before default abort 257 expect -re {Now listening on: ([^\r]+)\r} { 258 set url $expect_out(1,string) 259 } 260 expect "Application started. Press Ctrl+C to shut down." 261 set output [exec curl -sSf $url] 262 if {$output != "Hello World!"} { 263 send_error "Unexpected output: $output\n" 264 exit 1 265 } 266 send \x03 267 expect_before timeout abort 268 expect eof 269 catch wait result 270 exit [lindex $result 3] 271 EOF 272 touch $out 273 ''; 274 runAllowNetworking = true; 275 }; 276 in 277 unwrapped.passthru.tests or { } 278 // { 279 version = testers.testVersion { 280 package = finalAttrs.finalPackage; 281 command = "HOME=$(mktemp -d) dotnet " + (if type == "sdk" then "--version" else "--info"); 282 }; 283 } 284 // lib.optionalAttrs (type == "sdk") ({ 285 buildDotnetModule = recurseIntoAttrs ( 286 (pkgs.appendOverlays [ 287 (self: super: { 288 dotnet-sdk = finalAttrs.finalPackage; 289 dotnet-runtime = finalAttrs.finalPackage.runtime; 290 }) 291 ]).callPackage 292 ../../../test/dotnet/default.nix 293 { } 294 ); 295 296 console = lib.recurseIntoAttrs { 297 # yes, older SDKs omit the comma 298 cs = mkConsoleTests "C#" "cs" "Hello,?\\ World!"; 299 fs = mkConsoleTests "F#" "fs" "Hello\\ from\\ F#"; 300 vb = mkConsoleTests "VB" "vb" "Hello,?\\ World!"; 301 }; 302 303 web = lib.recurseIntoAttrs { 304 cs = mkWebTest "C#" "cs"; 305 fs = mkWebTest "F#" "fs"; 306 }; 307 }); 308 }; 309})