-
Notifications
You must be signed in to change notification settings - Fork 596
Expand file tree
/
Copy pathdotnet-helpers.sh
More file actions
244 lines (226 loc) · 9.68 KB
/
dotnet-helpers.sh
File metadata and controls
244 lines (226 loc) · 9.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#!/bin/bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
# Maintainer: The Dev Container spec maintainers
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
DOTNET_RELEASES_INDEX_URL="${DOTNET_RELEASES_MIRROR:-https://builds.dotnet.microsoft.com/dotnet}/release-metadata/releases-index.json"
# Prints the latest active dotnet version from the releases index.
# Usage: fetch_latest_version [<target>]
# With no target, resolves the latest SDK version.
# With "sdk", resolves the latest SDK version explicitly.
# With "dotnet" or "aspnetcore", resolves the latest runtime version.
# Note: the upstream releases index only distinguishes SDK vs runtime for
# latest resolution, so "dotnet" and "aspnetcore" currently resolve to the
# same version.
# Example: fetch_latest_version
# Example: fetch_latest_version "sdk"
# Example: fetch_latest_version "dotnet"
# Example: fetch_latest_version "aspnetcore"
fetch_latest_version() {
local target="$1"
local version_field=""
local releases_index=""
case "$target" in
""|sdk)
version_field="latest-sdk"
;;
dotnet|aspnetcore)
version_field="latest-runtime"
;;
*)
echo "Unsupported target '$target'. Expected 'sdk', 'dotnet', or 'aspnetcore'." >&2
return 1
;;
esac
releases_index="$(wget -qO- "$DOTNET_RELEASES_INDEX_URL")" || return $?
printf '%s\n' "$releases_index" \
| jq -er --arg version_field "$version_field" '
.["releases-index"]
| map(
select(."support-phase" == "active")
| .[$version_field]
)
| .[0]
'
}
# Installs a version of the .NET SDK
# Usage: install_sdk <version> [<quality>]
# Example: install_sdk "9.0"
# Example: install_sdk "10.0" "preview"
install_sdk() {
local inputVersion="$1" # Could be 'latest', 'lts', 'X.Y', 'X.Y.Z', 'X.Y.4xx', or base channel when paired with quality
local quality="$2" # Optional quality: GA, preview, daily (empty implies GA)
local version=""
local channel=""
if [[ "$inputVersion" == "latest" ]]; then
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
version=$(fetch_latest_version)
elif [[ "$inputVersion" == "lts" ]]; then
# When user input is 'lts'
# Then version=latest, channel=LTS
version="latest"
channel="LTS"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
# When user input is form 'A.B' like '3.1'
# Then version=latest, channel=3.1
version="latest"
channel="$inputVersion"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]xx$ ]]; then
# When user input is form 'A.B.Cxx' like '6.0.4xx'
# Then version=latest, channel=6.0.4xx
version="latest"
channel="$inputVersion"
else
# Assume version is an exact version string like '6.0.413' or '8.0.100-rc.2.23425.18'
version="$inputVersion"
fi
local cmd=("$DOTNET_INSTALL_SCRIPT" "--version" "$version" "--install-dir" "$DOTNET_ROOT")
if [ -n "${DOTNET_RELEASES_MIRROR:-}" ]; then
cmd+=("--azure-feed" "${DOTNET_RELEASES_MIRROR}")
fi
if [ -n "$channel" ]; then
cmd+=("--channel" "$channel")
fi
if [ -n "$quality" ]; then
cmd+=("--quality" "$quality")
fi
echo "Executing ${cmd[*]}"
"${cmd[@]}"
}
# Installs a version of the .NET Runtime
# Usage: install_runtime <runtime> <version> [<quality>]
# Example: install_runtime "dotnet" "9.0"
# Example: install_runtime "aspnetcore" "10.0" "preview"
install_runtime() {
local runtime="$1"
local inputVersion="$2" # Could be 'latest', 'lts', 'X.Y', 'X.Y.Z'
local quality="$3" # Optional quality: GA, preview, daily (empty implies GA)
local version=""
local channel=""
if [[ "$inputVersion" == "latest" ]]; then
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
version=$(fetch_latest_version "$runtime")
elif [[ "$inputVersion" == "lts" ]]; then
# When user input is 'lts'
# Then version=latest, channel=LTS
version="latest"
channel="LTS"
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
# When user input is form 'A.B' like '3.1'
# Then version=latest, channel=3.1
version="latest"
channel="$inputVersion"
else
# Assume version is an exact version string like '6.0.21' or '8.0.0-preview.7.23375.6'
version="$inputVersion"
fi
local cmd=("$DOTNET_INSTALL_SCRIPT" "--runtime" "$runtime" "--version" "$version" "--install-dir" "$DOTNET_ROOT" "--no-path")
if [ -n "${DOTNET_RELEASES_MIRROR:-}" ]; then
cmd+=("--azure-feed" "${DOTNET_RELEASES_MIRROR}")
fi
if [ -n "$channel" ]; then
cmd+=("--channel" "$channel")
fi
if [ -n "$quality" ]; then
cmd+=("--quality" "$quality")
fi
echo "Executing ${cmd[*]}"
"${cmd[@]}"
}
# Installs one or more .NET workloads
# Usage: install_workload <workload_id> [<workload_id> ...]
# Reference: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-workload-install
install_workloads() {
local workloads="$@"
echo "Installing .NET workload(s) $workloads"
dotnet workload install $workloads --temp-dir /tmp/dotnet-workload-temp-dir
# Clean up
rm -r /tmp/dotnet-workload-temp-dir
}
# Input: version spec possibly containing -preview or -daily
# Supports channels in the forms:
# A.B (e.g. 10.0)
# A.B.Cxx (feature band e.g. 6.0.4xx)
# A.B-preview (adds quality)
# A.B-daily
# A.B.Cxx-preview
# A.B.Cxx-daily
# Output (stdout): "<clean_version> <quality>"
# - For channel specs (A.B or A.B.Cxx) without suffix -> quality is GA
# - For channel specs with -preview/-daily suffix -> quality is preview/daily
# - For exact version specs (contain a third numeric segment or prerelease labels beyond channel patterns, e.g. 8.0.100-rc.2.23502.2) -> quality is empty
# Examples:
# parse_version_and_quality "10.0-preview" => "10.0 preview"
# parse_version_and_quality "10.0-daily" => "10.0 daily"
# parse_version_and_quality "10.0" => "10.0 GA"
# parse_version_and_quality "6.0.4xx" => "6.0.4xx GA"
# parse_version_and_quality "6.0.4xx-preview" => "6.0.4xx preview"
# parse_version_and_quality "6.0.4xx-daily" => "6.0.4xx daily"
parse_version_and_quality() {
local input="$1"
local quality=""
local clean_version="$input"
# Match feature band with quality
if [[ "$input" =~ ^([0-9]+\.[0-9]+\.[0-9]xx)-(preview|daily)$ ]]; then
clean_version="${BASH_REMATCH[1]}"
quality="${BASH_REMATCH[2]}"
# Match simple channel with quality
elif [[ "$input" =~ ^([0-9]+\.[0-9]+)-(preview|daily)$ ]]; then
clean_version="${BASH_REMATCH[1]}"
quality="${BASH_REMATCH[2]}"
# Match plain feature band channel (defaults to GA)
elif [[ "$input" =~ ^[0-9]+\.[0-9]+\.[0-9]xx$ ]]; then
clean_version="$input"
quality="GA"
# Match simple channel (defaults to GA)
elif [[ "$input" =~ ^[0-9]+\.[0-9]+$ ]]; then
clean_version="$input"
quality="GA"
else
# Exact version (leave quality empty)
clean_version="$input"
quality=""
fi
echo "$clean_version" "$quality"
}
# Checks if the installed .NET SDK is at least the given major version.
# Returns 0 (true) if the SDK major version >= the specified version, 1 otherwise.
# Also returns 1 if no SDK is installed (e.g. runtime-only installs).
# Usage: is_at_least_sdk_version <major_version>
# Example: is_at_least_sdk_version 10
is_at_least_sdk_version() {
local required_major="$1"
local dotnet_version
dotnet_version=$("$DOTNET_ROOT/dotnet" --version 2>/dev/null || true)
local major_version="${dotnet_version%%.*}"
[[ "$major_version" =~ ^[0-9]+$ ]] && [ "$major_version" -ge "$required_major" ]
}
# Sets up dotnet tab completions for bash, zsh, and fish.
# The 'dotnet completions script' command is only available in .NET SDK 10+.
# Older SDKs and runtime-only installs will naturally skip this since the
# command won't be available.
# Reference: https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete
# Completion scripts are generated at install time and placed in the standard
# system-wide completion directories, which are auto-discovered by
# bash-completion, zsh, and fish without modifying any rc files.
install_completions() {
if ! is_at_least_sdk_version 10; then
echo "Skipping dotnet tab completions (requires SDK 10+)."
return
fi
echo "Setting up dotnet tab completions..."
# Bash: drop into the standard bash-completion directory
mkdir -p /usr/share/bash-completion/completions
"$DOTNET_ROOT/dotnet" completions script bash > /usr/share/bash-completion/completions/dotnet
# Zsh: drop into the standard site-functions directory
mkdir -p /usr/share/zsh/site-functions
"$DOTNET_ROOT/dotnet" completions script zsh > /usr/share/zsh/site-functions/_dotnet
# Fish: drop into the standard vendor completions directory
mkdir -p /usr/share/fish/vendor_completions.d
"$DOTNET_ROOT/dotnet" completions script fish > /usr/share/fish/vendor_completions.d/dotnet.fish
}