Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1#!/usr/bin/env nix-shell 2#!nix-shell -I nixpkgs=./. -i bash -p curl jq nix gnused 3# shellcheck shell=bash 4 5set -Eeuo pipefail 6shopt -s inherit_errexit 7 8trap 'exit 1' ERR 9 10rids=({linux-{,musl-}{arm,arm64,x64},osx-{arm64,x64},win-{arm64,x64,x86}}) 11 12release () { 13 local content="$1" 14 local version="$2" 15 16 jq -er '.releases[] | select(."release-version" == "'"$version"'")' <<< "$content" 17} 18 19release_files () { 20 local release="$1" 21 local expr="$2" 22 23 jq -er '[('"$expr"').files[] | select(.name | test("^.*.tar.gz$"))]' <<< "$release" 24} 25 26release_platform_attr () { 27 local release_files="$1" 28 local platform="$2" 29 local attr="$3" 30 31 jq -r '.[] | select((.rid == "'"$platform"'") and (.name | contains("-composite-") or contains("-pack-") | not)) | ."'"$attr"'"' <<< "$release_files" 32} 33 34platform_sources () { 35 local release_files="$1" 36 37 echo "srcs = {" 38 for rid in "${rids[@]}"; do 39 local url hash 40 41 url=$(release_platform_attr "$release_files" "$rid" url) 42 hash=$(release_platform_attr "$release_files" "$rid" hash) 43 44 [[ -z "$url" || -z "$hash" ]] && continue 45 46 hash=$(nix --extra-experimental-features nix-command hash convert --to sri --hash-algo sha512 "$hash") 47 48 echo " $rid = { 49 url = \"$url\"; 50 hash = \"$hash\"; 51 };" 52 done 53 echo " };" 54} 55 56nuget_index="$(curl -fsSL "https://api.nuget.org/v3/index.json")" 57 58get_nuget_resource() { 59 jq -er '.resources[] | select(."@type" == "'"$1"'")."@id"' <<<"$nuget_index" 60} 61 62nuget_package_base_url="$(get_nuget_resource "PackageBaseAddress/3.0.0")" 63nuget_registration_base_url="$(get_nuget_resource "RegistrationsBaseUrl/3.6.0")" 64 65generate_package_list() { 66 local version="$1" indent="$2" 67 shift 2 68 local pkgs=( "$@" ) pkg url hash catalog_url catalog hash_algorithm 69 70 for pkg in "${pkgs[@]}"; do 71 url=${nuget_package_base_url}${pkg,,}/${version,,}/${pkg,,}.${version,,}.nupkg 72 73 if hash=$(curl -s --head "$url" -o /dev/null -w '%header{x-ms-meta-sha512}') && [[ -n "$hash" ]]; then 74 # Undocumented fast path for nuget.org 75 # https://github.com/NuGet/NuGetGallery/issues/9433#issuecomment-1472286080 76 hash=$(nix --extra-experimental-features nix-command hash convert --to sri --hash-algo sha512 "$hash") 77 elif { 78 catalog_url=$(curl -sL --compressed "${nuget_registration_base_url}${pkg,,}/${version,,}.json" | jq -r ".catalogEntry") && [[ -n "$catalog_url" ]] && 79 catalog=$(curl -sL "$catalog_url") && [[ -n "$catalog" ]] && 80 hash_algorithm="$(jq -er '.packageHashAlgorithm' <<<"$catalog")"&& [[ -n "$hash_algorithm" ]] && 81 hash=$(jq -er '.packageHash' <<<"$catalog") && [[ -n "$hash" ]] 82 }; then 83 # Documented but slower path (requires 2 requests) 84 hash=$(nix --extra-experimental-features nix-command hash convert --to sri --hash-algo "${hash_algorithm,,}" "$hash") 85 elif hash=$(nix-prefetch-url "$url" --type sha512); then 86 # Fallback to downloading and hashing locally 87 echo "Failed to fetch hash from nuget for $url, falling back to downloading locally" >&2 88 hash=$(nix --extra-experimental-features nix-command hash convert --to sri --hash-algo sha512 "$hash") 89 else 90 echo "Failed to fetch hash for $url" >&2 91 exit 1 92 fi 93 94 echo "$indent(fetchNupkg { pname = \"${pkg}\"; version = \"${version}\"; hash = \"${hash}\"; })" 95 done 96} 97 98versionAtLeast () { 99 local cur_version=$1 min_version=$2 100 printf "%s\0%s" "$min_version" "$cur_version" | sort -zVC 101} 102 103# These packages are implicitly references by the build process, 104# based on the specific project configurations (RIDs, used features, etc.) 105# They are always referenced with the same version as the SDK used for building. 106# Since we lock nuget dependencies, when these packages are included in the generated 107# lock files (deps.nix), every update of SDK required those lock files to be 108# updated to reflect the new versions of these packages - otherwise, the build 109# would fail due to missing dependencies. 110# 111# Moving them to a separate list stored alongside the SDK package definitions, 112# and implicitly including them along in buildDotnetModule allows us 113# to make updating .NET SDK packages a lot easier - we now just update 114# the versions of these packages in one place, and all packages that 115# use buildDotnetModule continue building with the new .NET version without changes. 116# 117# Keep in mind that there is no canonical list of these implicitly 118# referenced packages - this list was created based on looking into 119# the deps.nix files of existing packages, and which dependencies required 120# updating after a SDK version bump. 121# 122# Due to this, make sure to check if new SDK versions introduce any new packages. 123# This should not happend in minor or bugfix updates, but probably happens 124# with every new major .NET release. 125aspnetcore_packages () { 126 local version=$1 127 local pkgs=( 128 Microsoft.AspNetCore.App.Ref 129 ) 130 131 generate_package_list "$version" ' ' "${pkgs[@]}" 132} 133 134aspnetcore_target_packages () { 135 local version=$1 136 local rid=$2 137 local pkgs=( 138 "Microsoft.AspNetCore.App.Runtime.$rid" 139 ) 140 141 generate_package_list "$version" ' ' "${pkgs[@]}" 142} 143 144netcore_packages () { 145 local version=$1 146 local pkgs=( 147 Microsoft.NETCore.DotNetAppHost 148 Microsoft.NETCore.App.Ref 149 ) 150 151 if ! versionAtLeast "$version" 9; then 152 pkgs+=( 153 Microsoft.NETCore.DotNetHost 154 Microsoft.NETCore.DotNetHostPolicy 155 Microsoft.NETCore.DotNetHostResolver 156 ) 157 fi 158 159 if versionAtLeast "$version" 7; then 160 pkgs+=( 161 Microsoft.DotNet.ILCompiler 162 ) 163 fi 164 165 if versionAtLeast "$version" 8; then 166 pkgs+=( 167 Microsoft.NET.ILLink.Tasks 168 ) 169 fi 170 171 generate_package_list "$version" ' ' "${pkgs[@]}" 172} 173 174netcore_host_packages () { 175 local version=$1 176 local rid=$2 177 local pkgs=( 178 "Microsoft.NETCore.App.Crossgen2.$rid" 179 ) 180 181 local min_ilcompiler= 182 case "$rid" in 183 linux-musl-arm) ;; 184 linux-arm) ;; 185 win-x86) ;; 186 osx-arm64) min_ilcompiler=8 ;; 187 *) min_ilcompiler=7 ;; 188 esac 189 190 if [[ -n "$min_ilcompiler" ]] && versionAtLeast "$version" "$min_ilcompiler"; then 191 pkgs+=( 192 "runtime.$rid.Microsoft.DotNet.ILCompiler" 193 ) 194 fi 195 196 generate_package_list "$version" ' ' "${pkgs[@]}" 197} 198 199netcore_target_packages () { 200 local version=$1 201 local rid=$2 202 local pkgs=( 203 "Microsoft.NETCore.App.Host.$rid" 204 "Microsoft.NETCore.App.Runtime.$rid" 205 "runtime.$rid.Microsoft.NETCore.DotNetAppHost" 206 ) 207 208 if ! versionAtLeast "$version" 9; then 209 pkgs+=( 210 "runtime.$rid.Microsoft.NETCore.DotNetHost" 211 "runtime.$rid.Microsoft.NETCore.DotNetHostPolicy" 212 "runtime.$rid.Microsoft.NETCore.DotNetHostResolver" 213 ) 214 case "$rid" in 215 linux-musl-arm*) ;; 216 win-arm64) ;; 217 *) pkgs+=( 218 "Microsoft.NETCore.App.Runtime.Mono.$rid" 219 ) ;; 220 esac 221 fi 222 223 generate_package_list "$version" ' ' "${pkgs[@]}" 224} 225 226usage () { 227 echo "Usage: $pname [[--sdk] [-o output] sem-version] ... 228Get updated dotnet src (platform - url & sha512) expressions for specified versions 229 230Exit codes: 231 0 Success 232 1 Failure 233 2 Release not found 234 235Examples: 236 $pname 6.0.14 7.0.201 - specific x.y.z versions 237 $pname 6.0 7.0 - latest x.y versions 238" >&2 239} 240 241update() { 242 local -r sem_version=$1 sdk=$2 243 local output=$3 244 245 local patch_specified=false 246 # Check if a patch was specified as an argument. 247 # If so, generate file for the specific version. 248 # If only x.y version was provided, get the latest patch 249 # version of the given x.y version. 250 if [[ "$sem_version" =~ ^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,} ]]; then 251 patch_specified=true 252 elif [[ ! "$sem_version" =~ ^[0-9]{1,}\.[0-9]{1,}$ ]]; then 253 usage 254 return 1 255 fi 256 257 : ${output:="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"/versions/$sem_version.nix} 258 echo "Generating $output" 259 260 # Make sure the x.y version is properly passed to .NET release metadata url. 261 # Then get the json file and parse it to find the latest patch release. 262 local major_minor content major_minor_patch 263 major_minor=$(sed 's/^\([0-9]*\.[0-9]*\).*$/\1/' <<< "$sem_version") 264 content=$(curl -fsSL https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/"$major_minor"/releases.json) 265 if [[ -n $sdk ]]; then 266 trap '' ERR 267 major_minor_patch=$( 268 jq -er --arg version "$sem_version" ' 269 .releases[] | 270 select(.sdks[].version == $version) | 271 ."release-version"' <<< "$content" || if [[ $? == 4 ]]; then exit 2; else exit 1; fi) 272 trap 'exit 1' ERR 273 else 274 major_minor_patch=$([ "$patch_specified" == true ] && echo "$sem_version" || jq -er '."latest-release"' <<< "$content") 275 fi 276 local major_minor_underscore=${major_minor/./_} 277 278 local release_content aspnetcore_version runtime_version 279 local -a sdk_versions 280 281 release_content=$(release "$content" "$major_minor_patch") 282 aspnetcore_version=$(jq -er '."aspnetcore-runtime".version' <<< "$release_content") 283 runtime_version=$(jq -er '.runtime.version' <<< "$release_content") 284 285 if [[ -n $sdk ]]; then 286 sdk_versions=("$sem_version") 287 else 288 mapfile -t sdk_versions < <(jq -er '.sdks[] | .version' <<< "$release_content" | sort -rn) 289 fi 290 291 # If patch was not specified, check if the package is already the latest version 292 # If it is, exit early 293 if [ "$patch_specified" == false ] && [ -f "$output" ]; then 294 local -a versions 295 IFS= readarray -d '' versions < <( 296 nix-instantiate --eval --json -E "{ output }: with (import output { 297 buildAspNetCore = { ... }: {}; 298 buildNetSdk = { version, ... }: { inherit version; }; 299 buildNetRuntime = { version, ... }: { inherit version; }; 300 fetchNupkg = { ... }: {}; 301 }); (x: builtins.deepSeq x x) [ 302 runtime_${major_minor_underscore}.version 303 sdk_${major_minor_underscore}.version 304 ]" --argstr output "$output" | jq -e --raw-output0 .[]) 305 if [[ "${versions[0]}" == "$major_minor_patch" && "${versions[1]}" == "${sdk_versions[0]}" ]]; then 306 echo "Nothing to update." 307 return 308 fi 309 fi 310 311 local aspnetcore_files runtime_files 312 aspnetcore_files="$(release_files "$release_content" .\"aspnetcore-runtime\")" 313 runtime_files="$(release_files "$release_content" .runtime)" 314 315 local channel_version support_phase 316 channel_version=$(jq -er '."channel-version"' <<< "$content") 317 support_phase=$(jq -er '."support-phase"' <<< "$content") 318 319 local aspnetcore_sources runtime_sources 320 aspnetcore_sources="$(platform_sources "$aspnetcore_files")" 321 runtime_sources="$(platform_sources "$runtime_files")" 322 323 result=$(mktemp -t dotnet-XXXXXX.nix) 324 trap "rm -f $result" TERM INT EXIT 325 326 ( 327 echo "{ buildAspNetCore, buildNetRuntime, buildNetSdk, fetchNupkg }: 328 329# v$channel_version ($support_phase) 330 331let 332 commonPackages = [" 333 aspnetcore_packages "${aspnetcore_version}" 334 netcore_packages "${runtime_version}" 335 echo " ]; 336 337 hostPackages = {" 338 for rid in "${rids[@]}"; do 339 echo " $rid = [" 340 netcore_host_packages "${runtime_version}" "$rid" 341 echo " ];" 342 done 343 echo " }; 344 345 targetPackages = {" 346 for rid in "${rids[@]}"; do 347 echo " $rid = [" 348 aspnetcore_target_packages "${aspnetcore_version}" "$rid" 349 netcore_target_packages "${runtime_version}" "$rid" 350 echo " ];" 351 done 352 echo " }; 353 354in rec { 355 release_$major_minor_underscore = \"$major_minor_patch\"; 356 357 aspnetcore_$major_minor_underscore = buildAspNetCore { 358 version = \"${aspnetcore_version}\"; 359 $aspnetcore_sources 360 }; 361 362 runtime_$major_minor_underscore = buildNetRuntime { 363 version = \"${runtime_version}\"; 364 $runtime_sources 365 };" 366 367 local -A feature_bands 368 unset latest_sdk 369 370 for sdk_version in "${sdk_versions[@]}"; do 371 local sdk_base_version=${sdk_version%-*} 372 local feature_band=${sdk_base_version:0:-2}xx 373 # sometimes one release has e.g. both 8.0.202 and 8.0.203 374 [[ ! ${feature_bands[$feature_band]+true} ]] || continue 375 feature_bands[$feature_band]=$sdk_version 376 local sdk_files sdk_sources 377 sdk_files="$(release_files "$release_content" ".sdks[] | select(.version == \"$sdk_version\")")" 378 sdk_sources="$(platform_sources "$sdk_files")" 379 local sdk_attrname=sdk_${feature_band//./_} 380 [[ -v latest_sdk ]] || local latest_sdk=$sdk_attrname 381 382 echo " 383 $sdk_attrname = buildNetSdk { 384 version = \"${sdk_version}\"; 385 $sdk_sources 386 inherit commonPackages hostPackages targetPackages; 387 runtime = runtime_$major_minor_underscore; 388 aspnetcore = aspnetcore_$major_minor_underscore; 389 };" 390 done 391 392 if [[ -n $sdk ]]; then 393 echo " 394 sdk = sdk_$major_minor_underscore; 395" 396 fi 397 398 echo " 399 sdk_$major_minor_underscore = $latest_sdk; 400}" 401 )> "$result" 402 403 nixfmt "$result" 404 cp "$result" "$output" 405 echo "Generated $output" 406} 407 408main () { 409 local pname sdk output 410 pname=$(basename "$0") 411 412 sdk= 413 output= 414 415 while [ $# -gt 0 ]; do 416 case $1 in 417 --sdk) 418 shift 419 sdk=1 420 ;; 421 -o) 422 shift 423 output=$1 424 shift 425 ;; 426 *) 427 update "$1" "$sdk" "$output" 428 shift 429 ;; 430 esac 431 done 432} 433 434main "$@"