diff --git a/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/default.nix b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/default.nix index 3e988c627219..9b4fcddebf1b 100644 --- a/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/default.nix +++ b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/default.nix @@ -1,111 +1,62 @@ { lib, - vscode-utils, - patchelf, - icu, stdenv, + vscode-utils, + autoPatchelfHook, + icu, openssl, + libz, + glibc, coreutils, }: let inherit (stdenv.hostPlatform) system; inherit (vscode-utils) buildVscodeMarketplaceExtension; + lockfile = lib.importJSON ./lockfile.json; extInfo = - let - baseBins = [ - ".roslyn/Microsoft.CodeAnalysis.LanguageServer" - ".razor/rzls" - ]; - linuxBins = baseBins ++ [ - ".debugger/vsdbg-ui" - ".debugger/vsdbg" - ]; - darwinBins = baseBins ++ [ - ".debugger/x86_64/vsdbg-ui" - ".debugger/x86_64/vsdbg" - ]; - in - { - x86_64-linux = { - arch = "linux-x64"; - hash = "sha256-uCayu7WU+qqiCDxxfO4j1aOypP+O49uNZMnfwq+hO4k="; - binaries = linuxBins; - }; - aarch64-linux = { - arch = "linux-arm64"; - hash = "sha256-b4Q3JWNdZtLlgxMUBpu+5ppJDILxjPHBZeMxsQHiDa0="; - binaries = linuxBins; - }; - x86_64-darwin = { - arch = "darwin-x64"; - hash = "sha256-uVI2PmHfhmuQMTCbwrGuLamC1DyjeLCZf41pjT891GE="; - binaries = darwinBins; - }; - aarch64-darwin = { - arch = "darwin-arm64"; - hash = "sha256-zNSvznX7nYTBexlkD49t3Ne66/u3paecZJZwMuPmSf4="; - binaries = darwinBins ++ [ - ".debugger/arm64/vsdbg-ui" - ".debugger/arm64/vsdbg" - ]; - }; - } - .${system} or (throw "Unsupported system: ${system}"); + (arch: { + inherit arch; + inherit (lockfile.${arch}) hash binaries; + }) + ( + { + x86_64-linux = "linux-x64"; + aarch64-linux = "linux-arm64"; + x86_64-darwin = "darwin-x64"; + aarch64-darwin = "darwin-arm64"; + } + .${system} or (throw "Unsupported system: ${system}") + ); in buildVscodeMarketplaceExtension { mktplcRef = { name = "csharp"; publisher = "ms-dotnettools"; - version = "2.39.29"; + inherit (lockfile) version; inherit (extInfo) hash arch; }; - nativeBuildInputs = [ patchelf ]; + nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ autoPatchelfHook ]; + buildInputs = lib.optionals stdenv.hostPlatform.isLinux [ + (lib.getLib stdenv.cc.cc) # libstdc++.so.6 + (lib.getLib glibc) # libgcc_s.so.1 + (lib.getLib libz) # libz.so.1 + ]; + runtimeDependencies = lib.optionals stdenv.hostPlatform.isLinux [ + (lib.getLib openssl) # libopenssl.so.3 + (lib.getLib icu) # libicui18n.so libicuuc.so + (lib.getLib libz) # libz.so.1 + ]; - postPatch = - '' - patchelf_add_icu_as_needed() { - declare elf="''${1?}" - declare icu_major_v="${lib.head (lib.splitVersion (lib.getVersion icu.name))}" + postPatch = '' + substituteInPlace dist/extension.js \ + --replace-fail 'uname -m' '${lib.getExe' coreutils "uname"} -m' - for icu_lib in icui18n icuuc icudata; do - patchelf --add-needed "lib''${icu_lib}.so.$icu_major_v" "$elf" - done - } + chmod +x ${lib.escapeShellArgs extInfo.binaries} + ''; - patchelf_common() { - declare elf="''${1?}" - - patchelf_add_icu_as_needed "$elf" - patchelf --add-needed "libssl.so" "$elf" - patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ - --set-rpath "${ - lib.makeLibraryPath [ - stdenv.cc.cc - openssl - icu.out - ] - }:\$ORIGIN" \ - "$elf" - } - - substituteInPlace dist/extension.js \ - --replace 'uname -m' '${lib.getExe' coreutils "uname"} -m' - - '' - + (lib.concatStringsSep "\n" ( - map (bin: '' - chmod +x "${bin}" - '') extInfo.binaries - )) - + lib.optionalString stdenv.hostPlatform.isLinux ( - lib.concatStringsSep "\n" ( - map (bin: '' - patchelf_common "${bin}" - '') extInfo.binaries - ) - ); + passthru.updateScript = ./update.sh; meta = { description = "Official C# support for Visual Studio Code"; diff --git a/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/lockfile.json b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/lockfile.json new file mode 100644 index 000000000000..631e2520f818 --- /dev/null +++ b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/lockfile.json @@ -0,0 +1,46 @@ +{ + "version": "2.55.29", + "linux-x64": { + "hash": "sha256-3RQk5VNrI2sSUBCBfRTEsxjLqZkpoTELt/v+CIp94QU=", + "binaries": [ + ".debugger/createdump", + ".debugger/vsdbg", + ".debugger/vsdbg-ui", + ".razor/rzls", + ".roslyn/Microsoft.CodeAnalysis.LanguageServer" + ] + }, + "linux-arm64": { + "hash": "sha256-p8VbpeLtGDO3TKpjY9EuqDVyCDvZaQe9+KeAMTMulDc=", + "binaries": [ + ".debugger/createdump", + ".debugger/vsdbg", + ".debugger/vsdbg-ui", + ".razor/rzls", + ".roslyn/Microsoft.CodeAnalysis.LanguageServer" + ] + }, + "darwin-x64": { + "hash": "sha256-r85BNsxIXuQD20kjgqBvCLzTof4ExYDfbKG0zHaR86o=", + "binaries": [ + ".debugger/x86_64/createdump", + ".debugger/x86_64/vsdbg", + ".debugger/x86_64/vsdbg-ui", + ".razor/rzls", + ".roslyn/Microsoft.CodeAnalysis.LanguageServer" + ] + }, + "darwin-arm64": { + "hash": "sha256-p56EkUDxsukTx0FCCE2OrUBk3t2zj/kU6cdUVqdpfb8=", + "binaries": [ + ".debugger/arm64/createdump", + ".debugger/arm64/vsdbg", + ".debugger/arm64/vsdbg-ui", + ".debugger/x86_64/createdump", + ".debugger/x86_64/vsdbg", + ".debugger/x86_64/vsdbg-ui", + ".razor/rzls", + ".roslyn/Microsoft.CodeAnalysis.LanguageServer" + ] + } +} diff --git a/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/update.sh b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/update.sh new file mode 100755 index 000000000000..4d45e02b5b1f --- /dev/null +++ b/pkgs/applications/editors/vscode/extensions/ms-dotnettools.csharp/update.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env nix-shell +#!nix-shell -I nixpkgs=./. -i bash -p curl coreutils jq nix unzip +# shellcheck shell=bash +set -euo pipefail +shopt -s globstar +shopt -s dotglob + +export LC_ALL=C + +PUBLISHER=ms-dotnettools +EXTENSION=csharp +LOCKFILE=pkgs/applications/editors/vscode/extensions/$PUBLISHER.$EXTENSION/lockfile.json + +response=$(curl -s 'https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery' \ + -H 'accept: application/json;api-version=3.0-preview.1' \ + -H 'content-type: application/json' \ + --data-raw '{"filters":[{"criteria":[{"filterType":7,"value":"'"$PUBLISHER.$EXTENSION"'"}]}],"flags":16}') + +# Find the latest version compatible with stable vscode version +latest_version=$(jq --raw-output ' +.results[0].extensions[0].versions +| map(select(has("properties"))) +| map(select(.properties | map(select(.key == "Microsoft.VisualStudio.Code.Engine")) | .[0].value | test("\\^[0-9.]+$"))) +| map(select(.properties | map(select(.key == "Microsoft.VisualStudio.Code.PreRelease")) | .[0].value != "true")) +| .[0].version' <<<"$response") + +current_version=$(jq '.version' --raw-output <"$LOCKFILE") + +if [[ "$latest_version" == "$current_version" ]]; then + echo "Package is up to date." >&2 + exit 1 +fi + +# Return success if the specified file is an ELF object. +isELF() { + local fn="$1" + local fd + local magic + exec {fd}<"$fn" + read -r -n 4 -u "$fd" magic + exec {fd}<&- + if [ "$magic" = $'\177ELF' ]; then return 0; else return 1; fi +} + +# Return success if the specified file is a Mach-O object. +isMachO() { + local fn="$1" + local fd + local magic + exec {fd}<"$fn" + read -r -n 4 -u "$fd" magic + exec {fd}<&- + + # nix uses 'declare -F' in get-env.sh to retrieve the loaded functions. + # If we use the $'string' syntax instead of 'echo -ne' then 'declare' will print the raw characters and break nix. + # See https://github.com/NixOS/nixpkgs/pull/138334 and https://github.com/NixOS/nix/issues/5262. + + # https://opensource.apple.com/source/lldb/lldb-310.2.36/examples/python/mach_o.py.auto.html + if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xcf") || "$magic" = $(echo -ne "\xcf\xfa\xed\xfe") ]]; then + # MH_MAGIC_64 || MH_CIGAM_64 + return 0 + elif [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xce") || "$magic" = $(echo -ne "\xce\xfa\xed\xfe") ]]; then + # MH_MAGIC || MH_CIGAM + return 0 + elif [[ "$magic" = $(echo -ne "\xca\xfe\xba\xbe") || "$magic" = $(echo -ne "\xbe\xba\xfe\xca") ]]; then + # FAT_MAGIC || FAT_CIGAM + return 0 + else + return 1 + fi +} + +getDownloadUrl() { + nix-instantiate \ + --eval \ + --strict \ + --json \ + pkgs/applications/editors/vscode/extensions/mktplcExtRefToFetchArgs.nix \ + --attr url \ + --argstr publisher $PUBLISHER \ + --argstr name $EXTENSION \ + --argstr version "$latest_version" \ + --argstr arch "$1" | jq . --raw-output +} + +TEMP=$(mktemp --directory --tmpdir) +OUTPUT="$TEMP/lockfile.json" +trap 'rm -r "$TEMP"' EXIT + +HASH= +BINARIES=() +fetchMarketplace() { + arch="$1" + + echo " Downloading VSIX..." + if ! curl -sLo "$TEMP/$arch".zip "$(getDownloadUrl "$arch")"; then + echo " Failed to download extension for arch $arch" >&2 + exit 1 + fi + + HASH=$(nix hash file --type sha256 --sri "$TEMP/$arch".zip) + BINARIES=() + + echo " Extracting VSIX..." + mkdir "$TEMP/$arch" + if ! unzip "$TEMP/$arch".zip -d "$TEMP/$arch" >/dev/null; then + echo " Failed to unzip extension for arch $arch" >&2 + file "$TEMP/$arch".zip >&2 + exit 1 + fi + + echo " Listing binaries..." + for file in "$TEMP/$arch"/**/*; do + if [[ ! -f "$file" || "$file" == *.so || "$file" == *.dylib ]] || + (! isELF "$file" && ! isMachO "$file"); then + continue + fi + + echo " FOUND: ${file#"$TEMP/$arch/extension/"}" + BINARIES+=("${file#"$TEMP/$arch/extension/"}") + done + rm -r "${TEMP:?}/$arch" +} + +cat >"$OUTPUT" <>"$OUTPUT" + fi + firstArch=false + + echo "Getting data for $arch..." + fetchMarketplace "$arch" + + cat >>"$OUTPUT" <>"$OUTPUT" + fi + firstBin=false + + echo -n " \"$binary\"" >>"$OUTPUT" + done + echo -ne '\n ]\n }' >>"$OUTPUT" +done +echo -e '\n}' >>"$OUTPUT" + +mv "$OUTPUT" "$LOCKFILE"