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
6
7release () {
8 local content="$1"
9 local version="$2"
10
11 jq -r '.releases[] | select(."release-version" == "'"$version"'")' <<< "$content"
12}
13
14release_files () {
15 local release="$1"
16 local type="$2"
17
18 jq -r '[."'"$type"'".files[] | select(.name | test("^.*.tar.gz$"))]' <<< "$release"
19}
20
21release_platform_attr () {
22 local release_files="$1"
23 local platform="$2"
24 local attr="$3"
25
26 jq -r '.[] | select((.rid == "'"$platform"'") and (.name | contains("composite") | not)) | ."'"$attr"'"' <<< "$release_files"
27}
28
29platform_sources () {
30 local release_files="$1"
31 local platforms=( \
32 "x86_64-linux linux-x64" \
33 "aarch64-linux linux-arm64" \
34 "x86_64-darwin osx-x64" \
35 "aarch64-darwin osx-arm64" \
36 )
37
38 echo "srcs = {"
39 for kv in "${platforms[@]}"; do
40 local nix_platform=${kv%% *}
41 local ms_platform=${kv##* }
42
43 local url=$(release_platform_attr "$release_files" "$ms_platform" url)
44 local hash=$(release_platform_attr "$release_files" "$ms_platform" hash)
45
46 [[ -z "$url" || -z "$hash" ]] && continue
47 echo " $nix_platform = {
48 url = \"$url\";
49 sha512 = \"$hash\";
50 };"
51 done
52 echo " };"
53}
54
55generate_package_list() {
56 local version pkgs nuget_url
57 version="$1"
58 shift
59 pkgs=( "$@" )
60
61 nuget_url="$(curl -f "https://api.nuget.org/v3/index.json" | jq --raw-output '.resources[] | select(."@type" == "PackageBaseAddress/3.0.0")."@id"')"
62
63 for pkg in "${pkgs[@]}"; do
64 local url hash
65 url="${nuget_url}${pkg,,}/${version,,}/${pkg,,}.${version,,}.nupkg"
66 hash="$(nix-prefetch-url "$url")"
67 if [[ -z "$hash" ]]; then
68 echo "Failed to fetch hash for $url" >&2
69 exit 1
70 fi
71
72 echo " (fetchNuGet { pname = \"${pkg}\"; version = \"${version}\"; sha256 = \"${hash}\"; })"
73 done
74}
75
76version_older () {
77 cur_version=$1
78 max_version=$2
79 result=$(nix-instantiate -I ../../../../. \
80 --eval -E "(import <nixpkgs> {}).lib.versionOlder \"$cur_version\" \"$max_version\"")
81 if [[ "$result" == "true" ]]; then
82 return 0
83 else
84 return 1
85 fi
86}
87
88aspnetcore_packages () {
89 local version=$1
90 # These packages are implicitly references by the build process,
91 # based on the specific project configurations (RIDs, used features, etc.)
92 # They are always referenced with the same version as the SDK used for building.
93 # Since we lock nuget dependencies, when these packages are included in the generated
94 # lock files (deps.nix), every update of SDK required those lock files to be
95 # updated to reflect the new versions of these packages - otherwise, the build
96 # would fail due to missing dependencies.
97 #
98 # Moving them to a separate list stored alongside the SDK package definitions,
99 # and implicitly including them along in buildDotnetModule allows us
100 # to make updating .NET SDK packages a lot easier - we now just update
101 # the versions of these packages in one place, and all packages that
102 # use buildDotnetModule continue building with the new .NET version without changes.
103 #
104 # Keep in mind that there is no canonical list of these implicitly
105 # referenced packages - this list was created based on looking into
106 # the deps.nix files of existing packages, and which dependencies required
107 # updating after a SDK version bump.
108 #
109 # Due to this, make sure to check if new SDK versions introduce any new packages.
110 # This should not happend in minor or bugfix updates, but probably happens
111 # with every new major .NET release.
112 local pkgs=( \
113 "Microsoft.AspNetCore.App.Runtime.linux-arm" \
114 "Microsoft.AspNetCore.App.Runtime.linux-arm64" \
115 "Microsoft.AspNetCore.App.Runtime.linux-musl-arm64" \
116 "Microsoft.AspNetCore.App.Runtime.linux-musl-x64" \
117 "Microsoft.AspNetCore.App.Runtime.linux-x64" \
118 "Microsoft.AspNetCore.App.Runtime.osx-x64" \
119 "Microsoft.AspNetCore.App.Runtime.win-arm64" \
120 "Microsoft.AspNetCore.App.Runtime.win-x64" \
121 "Microsoft.AspNetCore.App.Runtime.win-x86" \
122 )
123
124 # These packages are currently broken on .NET 8
125 if version_older "$version" "8"; then
126 pkgs+=( \
127 "Microsoft.AspNetCore.App.Runtime.win-arm" \
128 )
129 fi
130
131 # Packages that only apply to .NET 6 and up
132 if ! version_older "$version" "6"; then
133 pkgs+=( \
134 "Microsoft.AspNetCore.App.Ref" \
135 "Microsoft.AspNetCore.App.Runtime.linux-musl-arm" \
136 "Microsoft.AspNetCore.App.Runtime.osx-arm64" \
137 )
138 fi
139
140
141 generate_package_list "$version" "${pkgs[@]}"
142}
143
144sdk_packages () {
145 local version=$1
146 # These packages are implicitly references by the build process,
147 # based on the specific project configurations (RIDs, used features, etc.)
148 # They are always referenced with the same version as the SDK used for building.
149 # Since we lock nuget dependencies, when these packages are included in the generated
150 # lock files (deps.nix), every update of SDK required those lock files to be
151 # updated to reflect the new versions of these packages - otherwise, the build
152 # would fail due to missing dependencies.
153 #
154 # Moving them to a separate list stored alongside the SDK package definitions,
155 # and implicitly including them along in buildDotnetModule allows us
156 # to make updating .NET SDK packages a lot easier - we now just update
157 # the versions of these packages in one place, and all packages that
158 # use buildDotnetModule continue building with the new .NET version without changes.
159 #
160 # Keep in mind that there is no canonical list of these implicitly
161 # referenced packages - this list was created based on looking into
162 # the deps.nix files of existing packages, and which dependencies required
163 # updating after a SDK version bump.
164 #
165 # Due to this, make sure to check if new SDK versions introduce any new packages.
166 # This should not happend in minor or bugfix updates, but probably happens
167 # with every new major .NET release.
168 local pkgs=( \
169 "Microsoft.NETCore.App.Host.linux-arm" \
170 "Microsoft.NETCore.App.Host.linux-arm64" \
171 "Microsoft.NETCore.App.Host.linux-musl-arm64" \
172 "Microsoft.NETCore.App.Host.linux-musl-x64" \
173 "Microsoft.NETCore.App.Host.linux-x64" \
174 "Microsoft.NETCore.App.Host.osx-x64" \
175 "Microsoft.NETCore.App.Host.win-arm64" \
176 "Microsoft.NETCore.App.Host.win-x64" \
177 "Microsoft.NETCore.App.Host.win-x86" \
178 "Microsoft.NETCore.App.Runtime.linux-arm" \
179 "Microsoft.NETCore.App.Runtime.linux-arm64" \
180 "Microsoft.NETCore.App.Runtime.linux-musl-arm64" \
181 "Microsoft.NETCore.App.Runtime.linux-musl-x64" \
182 "Microsoft.NETCore.App.Runtime.linux-x64" \
183 "Microsoft.NETCore.App.Runtime.osx-x64" \
184 "Microsoft.NETCore.App.Runtime.win-arm64" \
185 "Microsoft.NETCore.App.Runtime.win-x64" \
186 "Microsoft.NETCore.App.Runtime.win-x86" \
187 "Microsoft.NETCore.DotNetAppHost" \
188 "Microsoft.NETCore.DotNetHost" \
189 "Microsoft.NETCore.DotNetHostPolicy" \
190 "Microsoft.NETCore.DotNetHostResolver" \
191 "runtime.linux-arm64.Microsoft.NETCore.DotNetAppHost" \
192 "runtime.linux-arm64.Microsoft.NETCore.DotNetHost" \
193 "runtime.linux-arm64.Microsoft.NETCore.DotNetHostPolicy" \
194 "runtime.linux-arm64.Microsoft.NETCore.DotNetHostResolver" \
195 "runtime.linux-arm.Microsoft.NETCore.DotNetAppHost" \
196 "runtime.linux-arm.Microsoft.NETCore.DotNetHost" \
197 "runtime.linux-arm.Microsoft.NETCore.DotNetHostPolicy" \
198 "runtime.linux-arm.Microsoft.NETCore.DotNetHostResolver" \
199 "runtime.linux-musl-arm64.Microsoft.NETCore.DotNetAppHost" \
200 "runtime.linux-musl-arm64.Microsoft.NETCore.DotNetHost" \
201 "runtime.linux-musl-arm64.Microsoft.NETCore.DotNetHostPolicy" \
202 "runtime.linux-musl-arm64.Microsoft.NETCore.DotNetHostResolver" \
203 "runtime.linux-musl-x64.Microsoft.NETCore.DotNetAppHost" \
204 "runtime.linux-musl-x64.Microsoft.NETCore.DotNetHost" \
205 "runtime.linux-musl-x64.Microsoft.NETCore.DotNetHostPolicy" \
206 "runtime.linux-musl-x64.Microsoft.NETCore.DotNetHostResolver" \
207 "runtime.linux-x64.Microsoft.NETCore.DotNetAppHost" \
208 "runtime.linux-x64.Microsoft.NETCore.DotNetHost" \
209 "runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy" \
210 "runtime.linux-x64.Microsoft.NETCore.DotNetHostResolver" \
211 "runtime.osx-x64.Microsoft.NETCore.DotNetAppHost" \
212 "runtime.osx-x64.Microsoft.NETCore.DotNetHost" \
213 "runtime.osx-x64.Microsoft.NETCore.DotNetHostPolicy" \
214 "runtime.osx-x64.Microsoft.NETCore.DotNetHostResolver" \
215 "runtime.win-arm64.Microsoft.NETCore.DotNetAppHost" \
216 "runtime.win-arm64.Microsoft.NETCore.DotNetHost" \
217 "runtime.win-arm64.Microsoft.NETCore.DotNetHostPolicy" \
218 "runtime.win-arm64.Microsoft.NETCore.DotNetHostResolver" \
219 "runtime.win-x64.Microsoft.NETCore.DotNetAppHost" \
220 "runtime.win-x64.Microsoft.NETCore.DotNetHost" \
221 "runtime.win-x64.Microsoft.NETCore.DotNetHostPolicy" \
222 "runtime.win-x64.Microsoft.NETCore.DotNetHostResolver" \
223 "runtime.win-x86.Microsoft.NETCore.DotNetAppHost" \
224 "runtime.win-x86.Microsoft.NETCore.DotNetHost" \
225 "runtime.win-x86.Microsoft.NETCore.DotNetHostPolicy" \
226 "runtime.win-x86.Microsoft.NETCore.DotNetHostResolver" \
227 "Microsoft.NETCore.App.Host.linux-musl-arm" \
228 "Microsoft.NETCore.App.Host.osx-arm64" \
229 "Microsoft.NETCore.App.Runtime.linux-musl-arm" \
230 "Microsoft.NETCore.App.Runtime.osx-arm64" \
231 "Microsoft.NETCore.App.Ref" \
232 "Microsoft.NETCore.App.Runtime.Mono.linux-arm" \
233 "Microsoft.NETCore.App.Runtime.Mono.linux-arm64" \
234 "Microsoft.NETCore.App.Runtime.Mono.linux-musl-x64" \
235 "Microsoft.NETCore.App.Runtime.Mono.linux-x64" \
236 "Microsoft.NETCore.App.Runtime.Mono.osx-arm64" \
237 "Microsoft.NETCore.App.Runtime.Mono.osx-x64" \
238 "Microsoft.NETCore.App.Runtime.Mono.win-x64" \
239 "Microsoft.NETCore.App.Runtime.Mono.win-x86" \
240 "runtime.linux-musl-arm.Microsoft.NETCore.DotNetAppHost" \
241 "runtime.linux-musl-arm.Microsoft.NETCore.DotNetHost" \
242 "runtime.linux-musl-arm.Microsoft.NETCore.DotNetHostPolicy" \
243 "runtime.linux-musl-arm.Microsoft.NETCore.DotNetHostResolver" \
244 "runtime.osx-arm64.Microsoft.NETCore.DotNetAppHost" \
245 "runtime.osx-arm64.Microsoft.NETCore.DotNetHost" \
246 "runtime.osx-arm64.Microsoft.NETCore.DotNetHostPolicy" \
247 "runtime.osx-arm64.Microsoft.NETCore.DotNetHostResolver" \
248 "Microsoft.NETCore.App.Crossgen2.linux-musl-arm" \
249 "Microsoft.NETCore.App.Crossgen2.linux-musl-arm64" \
250 "Microsoft.NETCore.App.Crossgen2.linux-musl-x64" \
251 "Microsoft.NETCore.App.Crossgen2.linux-arm" \
252 "Microsoft.NETCore.App.Crossgen2.linux-arm64" \
253 "Microsoft.NETCore.App.Crossgen2.linux-x64" \
254 "Microsoft.NETCore.App.Crossgen2.osx-x64" \
255 "Microsoft.NETCore.App.Crossgen2.osx-arm64"
256 )
257
258 # These packages are currently broken on .NET 8
259 # When .NET 8 officialy launches, these should be checked and added back if fixed
260 if version_older "$version" "8"; then
261 pkgs+=( \
262 "Microsoft.NETCore.App.Host.win-arm" \
263 "Microsoft.NETCore.App.Runtime.win-arm" \
264 "runtime.win-arm.Microsoft.NETCore.DotNetAppHost" \
265 "runtime.win-arm.Microsoft.NETCore.DotNetHost" \
266 "runtime.win-arm.Microsoft.NETCore.DotNetHostPolicy" \
267 "runtime.win-arm.Microsoft.NETCore.DotNetHostResolver" \
268 "Microsoft.NETCore.App.Composite" \
269 )
270 fi
271
272 # Packages that only apply to .NET 7 and up
273 if ! version_older "$version" "7"; then
274 pkgs+=( \
275 "runtime.linux-arm64.Microsoft.DotNet.ILCompiler" \
276 "runtime.linux-musl-arm64.Microsoft.DotNet.ILCompiler" \
277 "runtime.linux-musl-x64.Microsoft.DotNet.ILCompiler" \
278 "runtime.linux-x64.Microsoft.DotNet.ILCompiler" \
279 "runtime.osx-x64.Microsoft.DotNet.ILCompiler" \
280 "runtime.win-arm64.Microsoft.DotNet.ILCompiler" \
281 "runtime.win-x64.Microsoft.DotNet.ILCompiler" \
282 )
283 fi
284
285 generate_package_list "$version" "${pkgs[@]}"
286}
287
288main () {
289 pname=$(basename "$0")
290 if [[ ! "$*" =~ ^.*[0-9]{1,}\.[0-9]{1,}.*$ ]]; then
291 echo "Usage: $pname [sem-versions]
292Get updated dotnet src (platform - url & sha512) expressions for specified versions
293
294Examples:
295 $pname 6.0.14 7.0.201 - specific x.y.z versions
296 $pname 6.0 7.0 - latest x.y versions
297" >&2
298 exit 1
299 fi
300
301 for sem_version in "$@"; do
302 echo "Generating ./versions/${sem_version}.nix"
303 patch_specified=false
304 # Check if a patch was specified as an argument.
305 # If so, generate file for the specific version.
306 # If only x.y version was provided, get the latest patch
307 # version of the given x.y version.
308 if [[ "$sem_version" =~ ^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$ ]]; then
309 patch_specified=true
310 elif [[ ! "$sem_version" =~ ^[0-9]{1,}\.[0-9]{1,}$ ]]; then
311 continue
312 fi
313
314 # Make sure the x.y version is properly passed to .NET release metadata url.
315 # Then get the json file and parse it to find the latest patch release.
316 major_minor=$(sed 's/^\([0-9]*\.[0-9]*\).*$/\1/' <<< "$sem_version")
317 content=$(curl -sL https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/"$major_minor"/releases.json)
318 major_minor_patch=$([ "$patch_specified" == true ] && echo "$sem_version" || jq -r '."latest-release"' <<< "$content")
319 major_minor_underscore=${major_minor/./_}
320
321 release_content=$(release "$content" "$major_minor_patch")
322 aspnetcore_version=$(jq -r '."aspnetcore-runtime".version' <<< "$release_content")
323 runtime_version=$(jq -r '.runtime.version' <<< "$release_content")
324 sdk_version=$(jq -r '.sdk.version' <<< "$release_content")
325
326 # If patch was not specified, check if the package is already the latest version
327 # If it is, exit early
328 if [ "$patch_specified" == false ] && [ -f "./versions/${sem_version}.nix" ]; then
329 current_version=$(nix-instantiate --eval -E "(import ./versions/${sem_version}.nix { \
330 buildAspNetCore = { ... }: {}; \
331 buildNetRuntime = { ... }: {}; \
332 buildNetSdk = { version, ... }: version; \
333 }).sdk_${major_minor_underscore}" | jq -r)
334
335 if [[ "$current_version" == "$sdk_version" ]]; then
336 echo "Nothing to update."
337 exit
338 fi
339 fi
340
341 aspnetcore_files="$(release_files "$release_content" "aspnetcore-runtime")"
342 runtime_files="$(release_files "$release_content" "runtime")"
343 sdk_files="$(release_files "$release_content" "sdk")"
344
345 channel_version=$(jq -r '."channel-version"' <<< "$content")
346 support_phase=$(jq -r '."support-phase"' <<< "$content")
347
348 result=$(mktemp)
349 trap "rm -f $result" TERM INT EXIT
350
351 echo "{ buildAspNetCore, buildNetRuntime, buildNetSdk }:
352
353# v$channel_version ($support_phase)
354{
355 aspnetcore_$major_minor_underscore = buildAspNetCore {
356 version = \"${aspnetcore_version}\";
357 $(platform_sources "$aspnetcore_files")
358 };
359
360 runtime_$major_minor_underscore = buildNetRuntime {
361 version = \"${runtime_version}\";
362 $(platform_sources "$runtime_files")
363 };
364
365 sdk_$major_minor_underscore = buildNetSdk {
366 version = \"${sdk_version}\";
367 $(platform_sources "$sdk_files")
368 packages = { fetchNuGet }: [
369$(aspnetcore_packages "${aspnetcore_version}")
370$(sdk_packages "${runtime_version}")
371 ];
372 };
373}" > "${result}"
374
375 cp "${result}" "./versions/${sem_version}.nix"
376 echo "Generated ./versions/${sem_version}.nix"
377 done
378}
379
380main "$@"