diff --git a/pkgs/misc/vscode-extensions/mktplcExtRefToFetchArgs.nix b/pkgs/misc/vscode-extensions/mktplcExtRefToFetchArgs.nix new file mode 100644 index 000000000000..21bdd0f6d7b1 --- /dev/null +++ b/pkgs/misc/vscode-extensions/mktplcExtRefToFetchArgs.nix @@ -0,0 +1,8 @@ +ext: +{ + url = "https://${ext.publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${ext.publisher}/extension/${ext.name}/${ext.version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"; + sha256 = ext.sha256; + # The `*.vsix` file is in the end a simple zip file. Change the extension + # so that existing `unzip` hooks takes care of the unpacking. + name = "${ext.publisher}-${ext.name}.zip"; +} diff --git a/pkgs/misc/vscode-extensions/vscode-utils.nix b/pkgs/misc/vscode-extensions/vscode-utils.nix index 5d446b025d7a..448bc81c917c 100644 --- a/pkgs/misc/vscode-extensions/vscode-utils.nix +++ b/pkgs/misc/vscode-extensions/vscode-utils.nix @@ -1,13 +1,6 @@ -{ stdenv, lib, fetchurl, unzip }: +{ stdenv, lib, writeShellScriptBin, fetchurl, vscode, unzip }: let - mktplcExtRefToFetchArgs = ext: { - url = "https://${ext.publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${ext.publisher}/extension/${ext.name}/${ext.version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"; - sha256 = ext.sha256; - # The `*.vsix` file is in the end a simple zip file. Change the extension - # so that existing `unzip` hooks takes care of the unpacking. - name = "${ext.publisher}-${ext.name}.zip"; - }; buildVscodeExtension = a@{ name, @@ -34,6 +27,7 @@ let buildInputs = [ unzip ] ++ buildInputs; installPhase = '' + runHook preInstall mkdir -p "$out/$installPrefix" @@ -44,9 +38,8 @@ let }); - fetchVsixFromVscodeMarketplace = mktplcExtRef: - fetchurl((mktplcExtRefToFetchArgs mktplcExtRef)); + fetchurl((import ./mktplcExtRefToFetchArgs.nix mktplcExtRef)); buildVscodeMarketplaceExtension = a@{ name ? "", @@ -79,10 +72,24 @@ let extensionsFromVscodeMarketplace = mktplcExtRefList: builtins.map extensionFromVscodeMarketplace mktplcExtRefList; -in + vscodeWithConfiguration = (userParams : import ./vscodeWithConfiguration.nix { + inherit lib vscode extensionsFromVscodeMarketplace writeShellScriptBin; + } // userParams); + + + vscodeExts2nix = (userParams : import ./vscodeExts2nix.nix { + inherit lib vscode; + } // userParams); + + vscodeEnv = (userParams : import ./vscodeEnv.nix { + inherit lib writeShellScriptBin extensionsFromVscodeMarketplace vscode; + } // userParams ); + +in { inherit fetchVsixFromVscodeMarketplace buildVscodeExtension buildVscodeMarketplaceExtension extensionFromVscodeMarketplace - extensionsFromVscodeMarketplace; + extensionsFromVscodeMarketplace + vscodeWithConfiguration vscodeExts2nix vscodeEnv; } diff --git a/pkgs/misc/vscode-extensions/vscodeEnv.nix b/pkgs/misc/vscode-extensions/vscodeEnv.nix new file mode 100644 index 000000000000..7c1bb255b850 --- /dev/null +++ b/pkgs/misc/vscode-extensions/vscodeEnv.nix @@ -0,0 +1,40 @@ +#use vscodeWithConfiguration and vscodeExts2nix to create vscode exetuable that when exits(vscode) will update the mutable extension file, which is imported when getting evaluated by nix. +{ pkgs ? import {} +, lib ? pkgs.lib +, writeShellScriptBin ? pkgs.writeShellScriptBin +, extensionsFromVscodeMarketplace ? pkgs.vscode-utils.extensionsFromVscodeMarketplace + +##User input + +, nixExtensions ? [] +# if file exists will use it and import the extensions in it into this dervation else will use empty extensions list +# this file will be created/updated by vscodeExts2nix when vscode exists +, mutableExtensionsFile ? ./extensions.nix +, vscodeExtsFolderName ? ".vscode-exts" +, vscode ? pkgs.vscode +}: +let + mutableExtensionsFilePath = builtins.toPath mutableExtensionsFile; + mutableExtensions = if builtins.pathExists mutableExtensionsFile + then import mutableExtensionsFilePath else []; + vscodeWithConfiguration = import ./vscodeWithConfiguration.nix { + inherit lib writeShellScriptBin vscode extensionsFromVscodeMarketplace + nixExtensions mutableExtensions vscodeExtsFolderName; + }; + + vscodeExts2nix = import ./vscodeExts2nix.nix { + inherit lib writeShellScriptBin; + extensionsToIgnore = nixExtensions; + extensions = mutableExtensions; + vscode = vscodeWithConfiguration; + }; + code = writeShellScriptBin "code" '' + ${vscodeWithConfiguration}/bin/code --wait "$@" + echo 'running vscodeExts2nix to update ${mutableExtensionsFilePath}...' + ${vscodeExts2nix}/bin/vscodeExts2nix > ${mutableExtensionsFilePath} + ''; +in +pkgs.buildEnv { + name = "vscodeEnv"; + paths = [ code vscodeExts2nix ]; +} diff --git a/pkgs/misc/vscode-extensions/vscodeExts2nix.nix b/pkgs/misc/vscode-extensions/vscodeExts2nix.nix new file mode 100644 index 000000000000..12fe09a2425c --- /dev/null +++ b/pkgs/misc/vscode-extensions/vscodeExts2nix.nix @@ -0,0 +1,44 @@ +# based on the passed vscode will stdout a nix expression with the installed vscode extensions +{ pkgs ? import {} +, lib ? pkgs.lib +, vscode ? pkgs.vscode +, writeShellScriptBin ? pkgs.writeShellScriptBin + +##User input + +, extensionsToIgnore ? [] +# will use those extensions to get sha256 if still exists when executed. +, extensions ? [] +}: +let + mktplcExtRefToFetchArgs = import ./mktplcExtRefToFetchArgs.nix; +in +writeShellScriptBin "vscodeExts2nix" '' + echo '[' + + for line in $(${vscode}/bin/code --list-extensions --show-versions \ + ${lib.optionalString (extensionsToIgnore != []) '' + | grep -v -i '^\(${lib.concatMapStringsSep "\\|" (e : ''${e.publisher}.${e.name}'') extensionsToIgnore}\)' + ''} + ) ; do + [[ $line =~ ([^.]*)\.([^@]*)@(.*) ]] + name=''${BASH_REMATCH[2]} + publisher=''${BASH_REMATCH[1]} + version=''${BASH_REMATCH[3]} + + extensions="${lib.concatMapStringsSep "." (e : ''${e.publisher}${e.name}@${e.sha256}'') extensions}" + reCurrentExt=$publisher$name"@([^.]*)" + if [[ $extensions =~ $reCurrentExt ]]; then + sha256=''${BASH_REMATCH[1]} + else + sha256=$( + nix-prefetch-url "${(mktplcExtRefToFetchArgs {publisher = ''"$publisher"''; name = ''"$name"''; version = ''"$version"'';}).url}" 2> /dev/null + ) + fi + + echo "{ name = \"''${name}\"; publisher = \"''${publisher}\"; version = \"''${version}\"; sha256 = \"''${sha256}\"; }" + done + + + echo ']' +'' diff --git a/pkgs/misc/vscode-extensions/vscodeWithConfiguration.nix b/pkgs/misc/vscode-extensions/vscodeWithConfiguration.nix new file mode 100644 index 000000000000..11282865c7c5 --- /dev/null +++ b/pkgs/misc/vscode-extensions/vscodeWithConfiguration.nix @@ -0,0 +1,39 @@ +# wrapper over vscode to control extensions per project (extensions folder will be created in execution path) +{ pkgs ? import {} +, lib ? pkgs.lib +, writeShellScriptBin ? pkgs.writeShellScriptBin +, extensionsFromVscodeMarketplace ? pkgs.vscode-utils.extensionsFromVscodeMarketplace + +##User input + +, vscode ? pkgs.vscode +# extensions to be symlinked into the project's extensions folder +, nixExtensions ? [] +# extensions to be copied into the project's extensions folder +, mutableExtensions ? [] +, vscodeExtsFolderName ? ".vscode-exts" +}: +let + nixExtsDrvs = extensionsFromVscodeMarketplace nixExtensions; + mutExtsDrvs = extensionsFromVscodeMarketplace mutableExtensions; + + #removed not defined extensions + rmExtensions = lib.optionalString (nixExtensions++mutableExtensions != []) '' + find ${vscodeExtsFolderName} -mindepth 1 -maxdepth 1 ${lib.concatMapStringsSep " " (e : ''! -iname ${e.publisher}.${e.name}'') (nixExtensions++mutableExtensions)} -exec sudo rm -rf {} \; + ''; + #copy mutable extension out of the nix store + cpExtensions = '' + ${lib.concatMapStringsSep "\n" (e : ''ln -sfn ${e}/share/vscode/extensions/* ${vscodeExtsFolderName}/'') nixExtsDrvs} + ${lib.concatMapStringsSep "\n" (e : '' + cp -a ${e}/share/vscode/extensions/${e.vscodeExtUniqueId} ${vscodeExtsFolderName}/${e.vscodeExtUniqueId}-${(lib.findSingle (ext: ''${ext.publisher}.${ext.name}'' == e.vscodeExtUniqueId) "" "m" mutableExtensions ).version} + '') mutExtsDrvs} + ''; +in + writeShellScriptBin "code" '' + if ! [[ "$@" =~ "--list-extension" ]]; then + mkdir -p ${vscodeExtsFolderName} + ${rmExtensions} + ${cpExtensions} + fi + ${vscode}/bin/code --extensions-dir ${vscodeExtsFolderName} "$@" + ''