dotnet.cmd (178 lines of code) (raw):
:<<"::CMDLITERAL"
@ECHO OFF
GOTO :CMDSCRIPT
::CMDLITERAL
set -eu
DOTNET_VERSION=9.0.101
SCRIPT_VERSION=v2
COMPANY_DIR="JetBrains"
TARGET_DIR="${TEMPDIR:-$HOME/.local/share}/$COMPANY_DIR/dotnet-cmd"
KEEP_ROSETTA2=false
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
retry_on_error () {
local n="$1"
shift
for i in $(seq 2 "$n"); do
"$@" 2>&1 && return || echo "WARNING: Command '$1' returned non-zero exit status $?, try again"
done
"$@"
}
is_linux_musl () {
(ldd --version 2>&1 || true) | grep -q musl
}
case $(uname) in
Darwin)
DOTNET_OS=osx
UNAME_ARCH=$(uname -m)
if ! $KEEP_ROSETTA2 && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || true)" = "1" ]; then
DOTNET_ARCH=arm64
fi
case $UNAME_ARCH in
arm64) DOTNET_ARCH=arm64;;
x86_64) DOTNET_ARCH=x64;;
*) echo "Unknown architecture $UNAME_ARCH" >&2; exit 1;;
esac;;
Linux)
DOTNET_OS=linux
UNAME_ARCH=$(linux$(getconf LONG_BIT) uname -m)
case $UNAME_ARCH in
armv7l | armv8l) is_linux_musl && DOTNET_ARCH=musl-arm || DOTNET_ARCH=arm;;
aarch64) is_linux_musl && DOTNET_ARCH=musl-arm64 || DOTNET_ARCH=arm64;;
x86_64) is_linux_musl && DOTNET_ARCH=musl-x64 || DOTNET_ARCH=x64;;
*) echo "Unknown architecture $UNAME_ARCH" >&2; exit 1;;
esac;;
*) echo "Unknown platform: $(uname)" >&2; exit 1;;
esac
DOTNET_URL=https://builds.dotnet.microsoft.com/dotnet/Sdk/$DOTNET_VERSION/dotnet-sdk-$DOTNET_VERSION-$DOTNET_OS-$DOTNET_ARCH.tar.gz
DOTNET_TARGET_DIR=$TARGET_DIR/sdk-$DOTNET_VERSION-$DOTNET_ARCH-$SCRIPT_VERSION
DOTNET_TEMP_FILE=$TARGET_DIR/temp-$SCRIPT_VERSION.tar.gz
if grep -q -x "$DOTNET_URL" "$DOTNET_TARGET_DIR/.flag" 2>/dev/null; then
# Everything is up-to-date in $DOTNET_TARGET_DIR, do nothing
true
else
while true; do # Note(k15tfu): for goto
mkdir -p "$TARGET_DIR"
LOCK_FILE="$TARGET_DIR/.dotnet-cmd-lock.pid"
TMP_LOCK_FILE="$TARGET_DIR/.tmp.$$.pid"
echo $$ >"$TMP_LOCK_FILE"
while ! ln "$TMP_LOCK_FILE" "$LOCK_FILE" 2>/dev/null; do
LOCK_OWNER=$(cat "$LOCK_FILE" 2>/dev/null || true)
while [ -n "$LOCK_OWNER" ] && ps -p $LOCK_OWNER >/dev/null; do
warn "Waiting for the process $LOCK_OWNER to finish bootstrap dotnet.cmd"
sleep 1
LOCK_OWNER=$(cat "$LOCK_FILE" 2>/dev/null || true)
# Hurry up, bootstrap is ready..
if grep -q -x "$DOTNET_URL" "$DOTNET_TARGET_DIR/.flag" 2>/dev/null; then
break 3 # Note(k15tfu): goto out of the outer if-else block.
fi
done
if [ -n "$LOCK_OWNER" ] && grep -q -x $LOCK_OWNER "$LOCK_FILE" 2>/dev/null; then
die "ERROR: The lock file $LOCK_FILE still exists on disk after the owner process $LOCK_OWNER exited"
fi
done
trap "rm -f \"$LOCK_FILE\"" EXIT
rm "$TMP_LOCK_FILE"
if ! grep -q -x "$DOTNET_URL" "$DOTNET_TARGET_DIR/.flag" 2>/dev/null; then
warn "Downloading $DOTNET_URL to $DOTNET_TEMP_FILE"
rm -f "$DOTNET_TEMP_FILE"
if command -v curl >/dev/null 2>&1; then
if [ -t 1 ]; then CURL_PROGRESS="--progress-bar"; else CURL_PROGRESS="--silent --show-error"; fi
retry_on_error 5 curl -L $CURL_PROGRESS --output "${DOTNET_TEMP_FILE}" "$DOTNET_URL"
elif command -v wget >/dev/null 2>&1; then
if [ -t 1 ]; then WGET_PROGRESS=""; else WGET_PROGRESS="-nv"; fi
retry_on_error 5 wget $WGET_PROGRESS -O "${DOTNET_TEMP_FILE}" "$DOTNET_URL"
else
die "ERROR: Please install wget or curl"
fi
warn "Extracting $DOTNET_TEMP_FILE to $DOTNET_TARGET_DIR"
rm -rf "$DOTNET_TARGET_DIR"
mkdir -p "$DOTNET_TARGET_DIR"
tar -x -f "$DOTNET_TEMP_FILE" -C "$DOTNET_TARGET_DIR"
rm -f "$DOTNET_TEMP_FILE"
echo "$DOTNET_URL" >"$DOTNET_TARGET_DIR/.flag"
fi
rm "$LOCK_FILE"
break
done
fi
if [ ! -x "$DOTNET_TARGET_DIR/dotnet" ]; then
die "Unable to find dotnet under $DOTNET_TARGET_DIR"
fi
exec "$DOTNET_TARGET_DIR/dotnet" "$@"
:CMDSCRIPT
setlocal
set DOTNET_VERSION=9.0.101
set SCRIPT_VERSION=v2
set COMPANY_NAME=JetBrains
set TARGET_DIR=%LOCALAPPDATA%\%COMPANY_NAME%\dotnet-cmd\
for /f "tokens=3 delims= " %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v "PROCESSOR_ARCHITECTURE"') do set ARCH=%%a
if "%ARCH%"=="ARM" (set DOTNET_ARCH=arm) else (
if "%ARCH%"=="ARM64" (set DOTNET_ARCH=arm64) else (
if "%ARCH%"=="AMD64" (set DOTNET_ARCH=x64) else (
if "%ARCH%"=="x86" (set DOTNET_ARCH=x86) else (
echo Unknown Windows architecture
goto fail
))))
set DOTNET_URL=https://builds.dotnet.microsoft.com/dotnet/Sdk/%DOTNET_VERSION%/dotnet-sdk-%DOTNET_VERSION%-win-%DOTNET_ARCH%.zip
set DOTNET_TARGET_DIR=%TARGET_DIR%sdk-%DOTNET_VERSION%-%DOTNET_ARCH%-%SCRIPT_VERSION%\
set DOTNET_TEMP_FILE=%TARGET_DIR%temp-%SCRIPT_VERSION%.zip
set POWERSHELL=%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
if not exist "%DOTNET_TARGET_DIR%.flag" goto downloadAndExtractDotNet
set /p CURRENT_FLAG=<"%DOTNET_TARGET_DIR%.flag"
if "%CURRENT_FLAG%" == "%DOTNET_URL%" goto continueWithDotNet
:downloadAndExtractDotNet
set DOWNLOAD_AND_EXTRACT_DOTNET_PS1= ^
Set-StrictMode -Version 3.0; ^
$ErrorActionPreference = 'Stop'; ^
^
$createdNew = $false; ^
$lock = New-Object System.Threading.Mutex($true, 'Global\dotnet-cmd-lock', [ref]$createdNew); ^
if (-not $createdNew) { ^
Write-Host 'Waiting for the other process to finish bootstrap dotnet.cmd'; ^
[void]$lock.WaitOne(); ^
} ^
^
try { ^
if ((Get-Content '%DOTNET_TARGET_DIR%.flag' -ErrorAction Ignore) -ne '%DOTNET_URL%') { ^
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ^
Write-Host 'Downloading %DOTNET_URL% to %DOTNET_TEMP_FILE%'; ^
[void](New-Item '%TARGET_DIR%' -ItemType Directory -Force); ^
(New-Object Net.WebClient).DownloadFile('%DOTNET_URL%', '%DOTNET_TEMP_FILE%'); ^
^
Write-Host 'Extracting %DOTNET_TEMP_FILE% to %DOTNET_TARGET_DIR%'; ^
if (Test-Path '%DOTNET_TARGET_DIR%') { ^
Remove-Item '%DOTNET_TARGET_DIR%' -Recurse; ^
} ^
Add-Type -A 'System.IO.Compression.FileSystem'; ^
[IO.Compression.ZipFile]::ExtractToDirectory('%DOTNET_TEMP_FILE%', '%DOTNET_TARGET_DIR%'); ^
Remove-Item '%DOTNET_TEMP_FILE%'; ^
^
Set-Content '%DOTNET_TARGET_DIR%.flag' -Value '%DOTNET_URL%'; ^
} ^
} ^
finally { ^
$lock.ReleaseMutex(); ^
}
"%POWERSHELL%" -nologo -noprofile -Command %DOWNLOAD_AND_EXTRACT_DOTNET_PS1%
if errorlevel 1 goto fail
:continueWithDotNet
if not exist "%DOTNET_TARGET_DIR%\dotnet.exe" (
echo Unable to find dotnet.exe under %DOTNET_TARGET_DIR%
goto fail
)
REM Prevent globally installed .NET Core from leaking into this runtime's lookup
SET DOTNET_MULTILEVEL_LOOKUP=0
call "%DOTNET_TARGET_DIR%\dotnet.exe" %*
exit /B %ERRORLEVEL%
endlocal
:fail
echo "FAIL"
exit /b 1