Unverified Commit 978aa3f8 authored by Steven's avatar Steven Committed by GitHub

Use new CDN for dotnet builds (#1230)

The azureedge.net domain might stop working as detailed in dotnet/core#9671

Changes in this PR:

dotnet: update the logic to determine the latest version
dotnet and oryx: copy latest dotnet-install script from
https://github.com/dotnet/install-scripts/blob/main/src/dotnet-install.sh
(Normally this happens automatically by a GitHub Action, but there is a sense of urgency here, so I did it manually)
Additional context

https://devblogs.microsoft.com/dotnet/critical-dotnet-install-links-are-changing/
https://build5nines.com/retirement-of-azureedge-net-dns-edg-io-business-closure-and-what-you-need-to-know/
parent 8e8e14f6
{ {
"id": "dotnet", "id": "dotnet",
"version": "2.1.3", "version": "2.2.0",
"name": "Dotnet CLI", "name": "Dotnet CLI",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet",
"description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.", "description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.",
......
...@@ -18,11 +18,11 @@ fetch_latest_version_in_channel() { ...@@ -18,11 +18,11 @@ fetch_latest_version_in_channel() {
local channel="$1" local channel="$1"
local runtime="$2" local runtime="$2"
if [ "$runtime" = "dotnet" ]; then if [ "$runtime" = "dotnet" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Runtime/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Runtime/$channel/latest.version"
elif [ "$runtime" = "aspnetcore" ]; then elif [ "$runtime" = "aspnetcore" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$channel/latest.version"
else else
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Sdk/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/$channel/latest.version"
fi fi
} }
......
...@@ -423,11 +423,17 @@ get_normalized_architecture_for_specific_sdk_version() { ...@@ -423,11 +423,17 @@ get_normalized_architecture_for_specific_sdk_version() {
# args: # args:
# version or channel - $1 # version or channel - $1
is_arm64_supported() { is_arm64_supported() {
#any channel or version that starts with the specified versions # Extract the major version by splitting on the dot
case "$1" in major_version="${1%%.*}"
( "1"* | "2"* | "3"* | "4"* | "5"*)
# Check if the major version is a valid number and less than 6
case "$major_version" in
[0-9]*)
if [ "$major_version" -lt 6 ]; then
echo false echo false
return 0 return 0
fi
;;
esac esac
echo true echo true
...@@ -950,6 +956,37 @@ get_absolute_path() { ...@@ -950,6 +956,37 @@ get_absolute_path() {
return 0 return 0
} }
# args:
# override - $1 (boolean, true or false)
get_cp_options() {
eval $invocation
local override="$1"
local override_switch=""
if [ "$override" = false ]; then
override_switch="-n"
# create temporary files to check if 'cp -u' is supported
tmp_dir="$(mktemp -d)"
tmp_file="$tmp_dir/testfile"
tmp_file2="$tmp_dir/testfile2"
touch "$tmp_file"
# use -u instead of -n if it's available
if cp -u "$tmp_file" "$tmp_file2" 2>/dev/null; then
override_switch="-u"
fi
# clean up
rm -f "$tmp_file" "$tmp_file2"
rm -rf "$tmp_dir"
fi
echo "$override_switch"
}
# args: # args:
# input_files - stdin # input_files - stdin
# root_path - $1 # root_path - $1
...@@ -961,15 +998,7 @@ copy_files_or_dirs_from_list() { ...@@ -961,15 +998,7 @@ copy_files_or_dirs_from_list() {
local root_path="$(remove_trailing_slash "$1")" local root_path="$(remove_trailing_slash "$1")"
local out_path="$(remove_trailing_slash "$2")" local out_path="$(remove_trailing_slash "$2")"
local override="$3" local override="$3"
local osname="$(get_current_os_name)" local override_switch="$(get_cp_options "$override")"
local override_switch=$(
if [ "$override" = false ]; then
if [ "$osname" = "linux-musl" ]; then
printf -- "-u";
else
printf -- "-n";
fi
fi)
cat | uniq | while read -r file_path; do cat | uniq | while read -r file_path; do
local path="$(remove_beginning_slash "${file_path#$root_path}")" local path="$(remove_beginning_slash "${file_path#$root_path}")"
...@@ -1243,6 +1272,61 @@ downloadwget() { ...@@ -1243,6 +1272,61 @@ downloadwget() {
return 0 return 0
} }
extract_stem() {
local url="$1"
# extract the protocol
proto="$(echo $1 | grep :// | sed -e's,^\(.*://\).*,\1,g')"
# remove the protocol
url="${1/$proto/}"
# extract the path (if any) - since we know all of our feeds have a first path segment, we can skip the first one. otherwise we'd use -f2- to get the full path
full_path="$(echo $url | grep / | cut -d/ -f2-)"
path="$(echo $full_path | cut -d/ -f2-)"
echo $path
}
check_url_exists() {
eval $invocation
local url="$1"
local code=""
if machine_has "curl"
then
code=$(curl --head -o /dev/null -w "%{http_code}" -s --fail "$url");
elif machine_has "wget"
then
# get the http response, grab the status code
server_response=$(wget -qO- --method=HEAD --server-response "$url" 2>&1)
code=$(echo "$server_response" | grep "HTTP/" | awk '{print $2}')
fi
if [ $code = "200" ]; then
return 0
else
return 1
fi
}
sanitize_redirect_url() {
eval $invocation
local url_stem
url_stem=$(extract_stem "$1")
say_verbose "Checking configured feeds for the asset at ${yellow:-}$url_stem${normal:-}"
for feed in "${feeds[@]}"
do
local trial_url="$feed/$url_stem"
say_verbose "Checking ${yellow:-}$trial_url${normal:-}"
if check_url_exists "$trial_url"; then
say_verbose "Found a match at ${yellow:-}$trial_url${normal:-}"
echo "$trial_url"
return 0
else
say_verbose "No match at ${yellow:-}$trial_url${normal:-}"
fi
done
return 1
}
get_download_link_from_aka_ms() { get_download_link_from_aka_ms() {
eval $invocation eval $invocation
...@@ -1295,6 +1379,11 @@ get_download_link_from_aka_ms() { ...@@ -1295,6 +1379,11 @@ get_download_link_from_aka_ms() {
return 1 return 1
fi fi
sanitized_redirect_url=$(sanitize_redirect_url "$aka_ms_download_link")
if [[ -n "$sanitized_redirect_url" ]]; then
aka_ms_download_link="$sanitized_redirect_url"
fi
say_verbose "The redirect location retrieved: '$aka_ms_download_link'." say_verbose "The redirect location retrieved: '$aka_ms_download_link'."
return 0 return 0
else else
...@@ -1306,7 +1395,9 @@ get_download_link_from_aka_ms() { ...@@ -1306,7 +1395,9 @@ get_download_link_from_aka_ms() {
get_feeds_to_use() get_feeds_to_use()
{ {
feeds=( feeds=(
"https://builds.dotnet.microsoft.com/dotnet"
"https://dotnetcli.azureedge.net/dotnet" "https://dotnetcli.azureedge.net/dotnet"
"https://ci.dot.net/public"
"https://dotnetbuilds.azureedge.net/public" "https://dotnetbuilds.azureedge.net/public"
) )
...@@ -1735,7 +1826,7 @@ do ...@@ -1735,7 +1826,7 @@ do
zip_path="$1" zip_path="$1"
;; ;;
-?|--?|-h|--help|-[Hh]elp) -?|--?|-h|--help|-[Hh]elp)
script_name="$(basename "$0")" script_name="dotnet-install.sh"
echo ".NET Tools Installer" echo ".NET Tools Installer"
echo "Usage:" echo "Usage:"
echo " # Install a .NET SDK of a given Quality from a given Channel" echo " # Install a .NET SDK of a given Quality from a given Channel"
......
{ {
"id": "oryx", "id": "oryx",
"version": "1.3.7", "version": "1.4.0",
"name": "Oryx", "name": "Oryx",
"description": "Installs the oryx CLI", "description": "Installs the oryx CLI",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/oryx", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/oryx",
......
...@@ -423,11 +423,17 @@ get_normalized_architecture_for_specific_sdk_version() { ...@@ -423,11 +423,17 @@ get_normalized_architecture_for_specific_sdk_version() {
# args: # args:
# version or channel - $1 # version or channel - $1
is_arm64_supported() { is_arm64_supported() {
#any channel or version that starts with the specified versions # Extract the major version by splitting on the dot
case "$1" in major_version="${1%%.*}"
( "1"* | "2"* | "3"* | "4"* | "5"*)
# Check if the major version is a valid number and less than 6
case "$major_version" in
[0-9]*)
if [ "$major_version" -lt 6 ]; then
echo false echo false
return 0 return 0
fi
;;
esac esac
echo true echo true
...@@ -950,6 +956,37 @@ get_absolute_path() { ...@@ -950,6 +956,37 @@ get_absolute_path() {
return 0 return 0
} }
# args:
# override - $1 (boolean, true or false)
get_cp_options() {
eval $invocation
local override="$1"
local override_switch=""
if [ "$override" = false ]; then
override_switch="-n"
# create temporary files to check if 'cp -u' is supported
tmp_dir="$(mktemp -d)"
tmp_file="$tmp_dir/testfile"
tmp_file2="$tmp_dir/testfile2"
touch "$tmp_file"
# use -u instead of -n if it's available
if cp -u "$tmp_file" "$tmp_file2" 2>/dev/null; then
override_switch="-u"
fi
# clean up
rm -f "$tmp_file" "$tmp_file2"
rm -rf "$tmp_dir"
fi
echo "$override_switch"
}
# args: # args:
# input_files - stdin # input_files - stdin
# root_path - $1 # root_path - $1
...@@ -961,15 +998,7 @@ copy_files_or_dirs_from_list() { ...@@ -961,15 +998,7 @@ copy_files_or_dirs_from_list() {
local root_path="$(remove_trailing_slash "$1")" local root_path="$(remove_trailing_slash "$1")"
local out_path="$(remove_trailing_slash "$2")" local out_path="$(remove_trailing_slash "$2")"
local override="$3" local override="$3"
local osname="$(get_current_os_name)" local override_switch="$(get_cp_options "$override")"
local override_switch=$(
if [ "$override" = false ]; then
if [ "$osname" = "linux-musl" ]; then
printf -- "-u";
else
printf -- "-n";
fi
fi)
cat | uniq | while read -r file_path; do cat | uniq | while read -r file_path; do
local path="$(remove_beginning_slash "${file_path#$root_path}")" local path="$(remove_beginning_slash "${file_path#$root_path}")"
...@@ -1243,6 +1272,61 @@ downloadwget() { ...@@ -1243,6 +1272,61 @@ downloadwget() {
return 0 return 0
} }
extract_stem() {
local url="$1"
# extract the protocol
proto="$(echo $1 | grep :// | sed -e's,^\(.*://\).*,\1,g')"
# remove the protocol
url="${1/$proto/}"
# extract the path (if any) - since we know all of our feeds have a first path segment, we can skip the first one. otherwise we'd use -f2- to get the full path
full_path="$(echo $url | grep / | cut -d/ -f2-)"
path="$(echo $full_path | cut -d/ -f2-)"
echo $path
}
check_url_exists() {
eval $invocation
local url="$1"
local code=""
if machine_has "curl"
then
code=$(curl --head -o /dev/null -w "%{http_code}" -s --fail "$url");
elif machine_has "wget"
then
# get the http response, grab the status code
server_response=$(wget -qO- --method=HEAD --server-response "$url" 2>&1)
code=$(echo "$server_response" | grep "HTTP/" | awk '{print $2}')
fi
if [ $code = "200" ]; then
return 0
else
return 1
fi
}
sanitize_redirect_url() {
eval $invocation
local url_stem
url_stem=$(extract_stem "$1")
say_verbose "Checking configured feeds for the asset at ${yellow:-}$url_stem${normal:-}"
for feed in "${feeds[@]}"
do
local trial_url="$feed/$url_stem"
say_verbose "Checking ${yellow:-}$trial_url${normal:-}"
if check_url_exists "$trial_url"; then
say_verbose "Found a match at ${yellow:-}$trial_url${normal:-}"
echo "$trial_url"
return 0
else
say_verbose "No match at ${yellow:-}$trial_url${normal:-}"
fi
done
return 1
}
get_download_link_from_aka_ms() { get_download_link_from_aka_ms() {
eval $invocation eval $invocation
...@@ -1295,6 +1379,11 @@ get_download_link_from_aka_ms() { ...@@ -1295,6 +1379,11 @@ get_download_link_from_aka_ms() {
return 1 return 1
fi fi
sanitized_redirect_url=$(sanitize_redirect_url "$aka_ms_download_link")
if [[ -n "$sanitized_redirect_url" ]]; then
aka_ms_download_link="$sanitized_redirect_url"
fi
say_verbose "The redirect location retrieved: '$aka_ms_download_link'." say_verbose "The redirect location retrieved: '$aka_ms_download_link'."
return 0 return 0
else else
...@@ -1306,7 +1395,9 @@ get_download_link_from_aka_ms() { ...@@ -1306,7 +1395,9 @@ get_download_link_from_aka_ms() {
get_feeds_to_use() get_feeds_to_use()
{ {
feeds=( feeds=(
"https://builds.dotnet.microsoft.com/dotnet"
"https://dotnetcli.azureedge.net/dotnet" "https://dotnetcli.azureedge.net/dotnet"
"https://ci.dot.net/public"
"https://dotnetbuilds.azureedge.net/public" "https://dotnetbuilds.azureedge.net/public"
) )
...@@ -1735,7 +1826,7 @@ do ...@@ -1735,7 +1826,7 @@ do
zip_path="$1" zip_path="$1"
;; ;;
-?|--?|-h|--help|-[Hh]elp) -?|--?|-h|--help|-[Hh]elp)
script_name="$(basename "$0")" script_name="dotnet-install.sh"
echo ".NET Tools Installer" echo ".NET Tools Installer"
echo "Usage:" echo "Usage:"
echo " # Install a .NET SDK of a given Quality from a given Channel" echo " # Install a .NET SDK of a given Quality from a given Channel"
......
...@@ -9,11 +9,11 @@ fetch_latest_version_in_channel() { ...@@ -9,11 +9,11 @@ fetch_latest_version_in_channel() {
local channel="$1" local channel="$1"
local runtime="$2" local runtime="$2"
if [ "$runtime" = "dotnet" ]; then if [ "$runtime" = "dotnet" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Runtime/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Runtime/$channel/latest.version"
elif [ "$runtime" = "aspnetcore" ]; then elif [ "$runtime" = "aspnetcore" ]; then
wget -qO- "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$channel/latest.version"
else else
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Sdk/$channel/latest.version" wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/$channel/latest.version"
fi fi
} }
......
...@@ -18,9 +18,6 @@ expected=$(fetch_latest_version) ...@@ -18,9 +18,6 @@ expected=$(fetch_latest_version)
check "Latest .NET SDK version installed" \ check "Latest .NET SDK version installed" \
is_dotnet_sdk_version_installed "$expected" is_dotnet_sdk_version_installed "$expected"
check "Build and run example project" \
dotnet run --project projects/net8.0
# Report results # Report results
# If any of the checks above exited with a non-zero exit code, the test will fail. # If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults reportResults
\ No newline at end of file
...@@ -18,9 +18,6 @@ expected=$(fetch_latest_version_in_channel "LTS") ...@@ -18,9 +18,6 @@ expected=$(fetch_latest_version_in_channel "LTS")
check "Latest LTS version installed" \ check "Latest LTS version installed" \
is_dotnet_sdk_version_installed "$expected" is_dotnet_sdk_version_installed "$expected"
check "Build and run example project" \
dotnet run --project projects/net8.0
# Report results # Report results
# If any of the checks above exited with a non-zero exit code, the test will fail. # If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults reportResults
\ No newline at end of file
...@@ -13,6 +13,9 @@ source dev-container-features-test-lib ...@@ -13,6 +13,9 @@ source dev-container-features-test-lib
source dotnet_env.sh source dotnet_env.sh
source dotnet_helpers.sh source dotnet_helpers.sh
check ".NET SDK 9.0 installed" \
is_dotnet_sdk_version_installed "9.0"
check ".NET SDK 8.0 installed" \ check ".NET SDK 8.0 installed" \
is_dotnet_sdk_version_installed "8.0" is_dotnet_sdk_version_installed "8.0"
...@@ -22,9 +25,33 @@ is_dotnet_sdk_version_installed "7.0" ...@@ -22,9 +25,33 @@ is_dotnet_sdk_version_installed "7.0"
check ".NET SDK 6.0 installed" \ check ".NET SDK 6.0 installed" \
is_dotnet_sdk_version_installed "6.0" is_dotnet_sdk_version_installed "6.0"
check ".NET SDK 5.0 installed" \
is_dotnet_sdk_version_installed "5.0"
check ".NET Core SDK 3.1 installed" \
is_dotnet_sdk_version_installed "3.1"
check "Build example class library" \ check "Build example class library" \
dotnet build projects/multitargeting dotnet build projects/multitargeting
check "Build and run .NET 9.0 project" \
dotnet run --project projects/net9.0
check "Build and run .NET 8.0 project" \
dotnet run --project projects/net8.0
check "Build and run .NET 7.0 project" \
dotnet run --project projects/net7.0
check "Build and run .NET 6.0 project" \
dotnet run --project projects/net6.0
check "Build and run .NET 5.0 project" \
dotnet run --project projects/net5.0
check "Build and run .NET Core 3.1 project" \
dotnet run --project projects/netcoreapp3.1
# Report results # Report results
# If any of the checks above exited with a non-zero exit code, the test will fail. # If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults reportResults
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net9.0;net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
using Newtonsoft.Json;
string json = """
{
"Name": "Inception",
"ReleaseDate": "2010-07-08T00:00:00",
"Genres": [
"Action",
"Thriller"
]
}
""";
Movie? m = JsonConvert.DeserializeObject<Movie>(json);
if (m == default)
{
Console.WriteLine("Decoding failed!");
}
else
{
Console.WriteLine($"Movie name: {m.Name}");
Console.WriteLine($"Release Date: {m.ReleaseDate}");
Console.WriteLine($"Genres: {string.Join(", ", m.Genres)}");
}
class Movie(string? name, DateTime releaseDate, List<string>? genres)
{
public string Name { get; set; } = name ?? "Default Name";
public DateTime ReleaseDate { get; set; } = releaseDate;
public List<string> Genres { get; set; } = genres ?? [];
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>
\ No newline at end of file
...@@ -3,12 +3,11 @@ ...@@ -3,12 +3,11 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -40,10 +40,13 @@ ...@@ -40,10 +40,13 @@
"remoteUser": "vscode", "remoteUser": "vscode",
"features": { "features": {
"dotnet": { "dotnet": {
"version": "8.0.100-preview.6.23330.14", "version": "9.0",
"additionalVersions": [ "additionalVersions": [
"8.0",
"7.0", "7.0",
"6.0" "6.0",
"5.0",
"3.1"
] ]
} }
} }
......
...@@ -24,9 +24,6 @@ expected=$(fetch_latest_version) ...@@ -24,9 +24,6 @@ expected=$(fetch_latest_version)
check "Latest .NET SDK version installed" \ check "Latest .NET SDK version installed" \
is_dotnet_sdk_version_installed "$expected" is_dotnet_sdk_version_installed "$expected"
check "Build and run example project" \
dotnet run --project projects/net8.0
# Report results # Report results
# If any of the checks above exited with a non-zero exit code, the test will fail. # If any of the checks above exited with a non-zero exit code, the test will fail.
reportResults reportResults
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment