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