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