diff --git a/pkgs/applications/editors/jetbrains/darwin.nix b/pkgs/applications/editors/jetbrains/darwin.nix index f771894f533d70d..e5c4dd7e4fc9946 100644 --- a/pkgs/applications/editors/jetbrains/darwin.nix +++ b/pkgs/applications/editors/jetbrains/darwin.nix @@ -10,27 +10,30 @@ , productShort ? product , src , version +, plugins ? [ ] +, buildNumber , ... }: let loname = lib.toLower productShort; in - stdenvNoCC.mkDerivation { - inherit pname meta src version; - desktopName = product; - installPhase = '' - runHook preInstall - APP_DIR="$out/Applications/${product}.app" - mkdir -p "$APP_DIR" - cp -Tr "${product}.app" "$APP_DIR" - mkdir -p "$out/bin" - cat << EOF > "$out/bin/${loname}" - open -na '$APP_DIR' --args "\$@" - EOF - chmod +x "$out/bin/${loname}" - runHook postInstall - ''; - nativeBuildInputs = [ undmg ]; - sourceRoot = "."; - } +stdenvNoCC.mkDerivation { + inherit pname meta src version plugins; + passthru.buildNumber = buildNumber; + desktopName = product; + installPhase = '' + runHook preInstall + APP_DIR="$out/Applications/${product}.app" + mkdir -p "$APP_DIR" + cp -Tr "${product}.app" "$APP_DIR" + mkdir -p "$out/bin" + cat << EOF > "$out/bin/${loname}" + open -na '$APP_DIR' --args "\$@" + EOF + chmod +x "$out/bin/${loname}" + runHook postInstall + ''; + nativeBuildInputs = [ undmg ]; + sourceRoot = "."; +} diff --git a/pkgs/applications/editors/jetbrains/default.nix b/pkgs/applications/editors/jetbrains/default.nix index 8450fea7acba53c..cc9dd914d59c034 100644 --- a/pkgs/applications/editors/jetbrains/default.nix +++ b/pkgs/applications/editors/jetbrains/default.nix @@ -1,5 +1,13 @@ -{ lib, stdenv, callPackage, fetchurl -, jdk, cmake, gdb, zlib, python3, icu +{ lib +, stdenv +, callPackage +, fetchurl +, jdk +, cmake +, gdb +, zlib +, python3 +, icu , lldb , dotnet-sdk_6 , maven @@ -27,9 +35,9 @@ let # Sorted alphabetically - buildClion = { pname, version, src, license, description, wmClass, ... }: + buildClion = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "CLion"; meta = with lib; { homepage = "https://www.jetbrains.com/clion/"; @@ -41,11 +49,10 @@ let maintainers = with maintainers; [ edwtjo mic92 ]; }; }).overrideAttrs (attrs: { - nativeBuildInputs = (attrs.nativeBuildInputs or []) ++ lib.optionals (stdenv.isLinux) [ + nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) ++ lib.optionals (stdenv.isLinux) [ autoPatchelfHook - patchelf ]; - buildInputs = (attrs.buildInputs or []) ++ lib.optionals (stdenv.isLinux) [ + buildInputs = (attrs.buildInputs or [ ]) ++ lib.optionals (stdenv.isLinux) [ python3 stdenv.cc.cc libdbusmenu @@ -70,16 +77,15 @@ let --replace-needed libcrypto.so.10 libcrypto.so autoPatchelf $PWD/bin - wrapProgram $out/bin/clion \ --set CL_JDK "${jdk}" ) ''; }); - buildDataGrip = { pname, version, src, license, description, wmClass, ... }: + buildDataGrip = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "DataGrip"; meta = with lib; { homepage = "https://www.jetbrains.com/datagrip/"; @@ -93,9 +99,9 @@ let }; }); - buildGateway = { pname, version, src, license, description, wmClass, product, ... }: + buildGateway = { pname, version, src, license, description, wmClass, buildNumber, product, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk product; + inherit pname version src wmClass jdk buildNumber product; productShort = "Gateway"; meta = with lib; { homepage = "https://www.jetbrains.com/remote-development/gateway/"; @@ -109,9 +115,9 @@ let }; }); - buildGoland = { pname, version, src, license, description, wmClass, ... }: + buildGoland = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "Goland"; meta = with lib; { homepage = "https://www.jetbrains.com/go/"; @@ -128,18 +134,16 @@ let postFixup = (attrs.postFixup or "") + lib.optionalString stdenv.isLinux '' interp="$(cat $NIX_CC/nix-support/dynamic-linker)" patchelf --set-interpreter $interp $out/goland/plugins/go-plugin/lib/dlv/linux/dlv - chmod +x $out/goland/plugins/go-plugin/lib/dlv/linux/dlv - # fortify source breaks build since delve compiles with -O0 wrapProgram $out/bin/goland \ --prefix CGO_CPPFLAGS " " "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" ''; }); - buildIdea = { pname, version, src, license, description, wmClass, product, ... }: + buildIdea = { pname, version, src, license, description, wmClass, buildNumber, product, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk product; + inherit pname version src wmClass jdk buildNumber product; productShort = "IDEA"; extraLdPath = [ zlib ]; extraWrapperArgs = [ @@ -160,9 +164,9 @@ let }; }); - buildMps = { pname, version, src, license, description, wmClass, product, ... }: + buildMps = { pname, version, src, license, description, wmClass, product, buildNumber, ... }: (mkJetBrainsProduct rec { - inherit pname version src wmClass jdk product; + inherit pname version src wmClass jdk buildNumber product; productShort = "MPS"; meta = with lib; { broken = (stdenv.isLinux && stdenv.isAarch64); @@ -178,9 +182,9 @@ let }; }); - buildPhpStorm = { pname, version, src, license, description, wmClass, ... }: + buildPhpStorm = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "PhpStorm"; meta = with lib; { homepage = "https://www.jetbrains.com/phpstorm/"; @@ -194,9 +198,9 @@ let }; }); - buildPycharm = { pname, version, src, license, description, wmClass, product, cythonSpeedup ? stdenv.isLinux, ... }: + buildPycharm = { pname, version, src, license, description, wmClass, buildNumber, product, cythonSpeedup ? stdenv.isLinux, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk product; + inherit pname version src wmClass jdk buildNumber product; productShort = "PyCharm"; meta = with lib; { broken = (stdenv.isLinux && stdenv.isAarch64); @@ -215,24 +219,24 @@ let providing you almost everything you need for your comfortable and productive development! ''; - maintainers = with maintainers; [ ]; + maintainers = with maintainers; [ genericnerdyusername ]; }; }).overrideAttrs (finalAttrs: previousAttrs: lib.optionalAttrs cythonSpeedup { buildInputs = with python3.pkgs; [ python3 setuptools ]; preInstall = '' - echo "compiling cython debug speedups" - if [[ -d plugins/python-ce ]]; then - ${python3.interpreter} plugins/python-ce/helpers/pydev/setup_cython.py build_ext --inplace - else - ${python3.interpreter} plugins/python/helpers/pydev/setup_cython.py build_ext --inplace - fi + echo "compiling cython debug speedups" + if [[ -d plugins/python-ce ]]; then + ${python3.interpreter} plugins/python-ce/helpers/pydev/setup_cython.py build_ext --inplace + else + ${python3.interpreter} plugins/python/helpers/pydev/setup_cython.py build_ext --inplace + fi ''; # See https://www.jetbrains.com/help/pycharm/2022.1/cython-speedups.html }); - buildRider = { pname, version, src, license, description, wmClass, ... }: + buildRider = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "Rider"; # icu is required by Rider.Backend extraLdPath = [ icu ]; @@ -261,9 +265,9 @@ let ''); }); - buildRubyMine = { pname, version, src, license, description, wmClass, ... }: + buildRubyMine = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "RubyMine"; meta = with lib; { homepage = "https://www.jetbrains.com/ruby/"; @@ -273,9 +277,9 @@ let }; }); - buildWebStorm = { pname, version, src, license, description, wmClass, ... }: + buildWebStorm = { pname, version, src, license, description, wmClass, buildNumber, ... }: (mkJetBrainsProduct { - inherit pname version src wmClass jdk; + inherit pname version src wmClass jdk buildNumber; product = "WebStorm"; meta = with lib; { homepage = "https://www.jetbrains.com/webstorm/"; @@ -297,7 +301,8 @@ in clion = buildClion rec { pname = "clion"; version = products.clion.version; - description = "C/C++ IDE. New. Intelligent. Cross-platform"; + buildNumber = products.clion.build_number; + description = "C/C++ IDE. New. Intelligent. Cross-platform"; license = lib.licenses.unfree; src = fetchurl { url = products.clion.url; @@ -310,6 +315,7 @@ in datagrip = buildDataGrip rec { pname = "datagrip"; version = products.datagrip.version; + buildNumber = products.datagrip.build_number; description = "Your Swiss Army Knife for Databases and SQL"; license = lib.licenses.unfree; src = fetchurl { @@ -324,6 +330,7 @@ in pname = "gateway"; product = "JetBrains Gateway"; version = products.gateway.version; + buildNumber = products.gateway.build_number; description = "Your single entry point to all remote development environments"; license = lib.licenses.unfree; src = fetchurl { @@ -337,6 +344,7 @@ in goland = buildGoland rec { pname = "goland"; version = products.goland.version; + buildNumber = products.goland.build_number; description = "Up and Coming Go IDE"; license = lib.licenses.unfree; src = fetchurl { @@ -351,6 +359,7 @@ in pname = "idea-community"; product = "IntelliJ IDEA CE"; version = products.idea-community.version; + buildNumber = products.idea-community.build_number; description = "Integrated Development Environment (IDE) by Jetbrains, community edition"; license = lib.licenses.asl20; src = fetchurl { @@ -365,6 +374,7 @@ in pname = "idea-ultimate"; product = "IntelliJ IDEA"; version = products.idea-ultimate.version; + buildNumber = products.idea-ultimate.build_number; description = "Integrated Development Environment (IDE) by Jetbrains, requires paid license"; license = lib.licenses.unfree; src = fetchurl { @@ -379,6 +389,7 @@ in pname = "mps"; product = "MPS ${products.mps.version}"; version = products.mps.version; + buildNumber = products.mps.build_number; description = "Create your own domain-specific language"; license = lib.licenses.asl20; src = fetchurl { @@ -392,6 +403,7 @@ in phpstorm = buildPhpStorm rec { pname = "phpstorm"; version = products.phpstorm.version; + buildNumber = products.phpstorm.build_number; description = "Professional IDE for Web and PHP developers"; license = lib.licenses.unfree; src = fetchurl { @@ -406,6 +418,7 @@ in pname = "pycharm-community"; product = "PyCharm CE"; version = products.pycharm-community.version; + buildNumber = products.pycharm-community.build_number; description = "PyCharm Community Edition"; license = lib.licenses.asl20; src = fetchurl { @@ -420,6 +433,7 @@ in pname = "pycharm-professional"; product = "PyCharm"; version = products.pycharm-professional.version; + buildNumber = products.pycharm-community.build_number; description = "PyCharm Professional Edition"; license = lib.licenses.unfree; src = fetchurl { @@ -433,6 +447,7 @@ in rider = buildRider rec { pname = "rider"; version = products.rider.version; + buildNumber = products.rider.build_number; description = "A cross-platform .NET IDE based on the IntelliJ platform and ReSharper"; license = lib.licenses.unfree; src = fetchurl { @@ -446,6 +461,7 @@ in ruby-mine = buildRubyMine rec { pname = "ruby-mine"; version = products.ruby-mine.version; + buildNumber = products.ruby-mine.build_number; description = "The Most Intelligent Ruby and Rails IDE"; license = lib.licenses.unfree; src = fetchurl { @@ -459,6 +475,7 @@ in webstorm = buildWebStorm rec { pname = "webstorm"; version = products.webstorm.version; + buildNumber = products.webstorm.build_number; description = "Professional IDE for Web and JavaScript development"; license = lib.licenses.unfree; src = fetchurl { @@ -469,4 +486,6 @@ in update-channel = products.webstorm.update-channel; }; + plugins = callPackage ./plugins { }; + } diff --git a/pkgs/applications/editors/jetbrains/linux.nix b/pkgs/applications/editors/jetbrains/linux.nix index 7443842e7bf9c60..c9145a25e0a1a83 100644 --- a/pkgs/applications/editors/jetbrains/linux.nix +++ b/pkgs/applications/editors/jetbrains/linux.nix @@ -1,25 +1,50 @@ -{ stdenv, lib, makeDesktopItem, makeWrapper, patchelf, writeText -, coreutils, gnugrep, which, git, unzip, libsecret, libnotify, e2fsprogs +{ stdenv +, lib +, makeDesktopItem +, makeWrapper +, patchelf +, writeText +, coreutils +, gnugrep +, which +, git +, unzip +, libsecret +, libnotify +, e2fsprogs , vmopts ? null }: -{ pname, product, productShort ? product, version, src, wmClass, jdk, meta, extraLdPath ? [], extraWrapperArgs ? [] }@args: - -let loName = lib.toLower productShort; - hiName = lib.toUpper productShort; - vmoptsName = loName - + lib.optionalString stdenv.hostPlatform.is64bit "64" - + ".vmoptions"; +{ pname +, product +, productShort ? product +, version +, src +, wmClass +, buildNumber +, jdk +, meta +, extraLdPath ? [ ] +, extraWrapperArgs ? [ ] +}@args: + +let + loName = lib.toLower productShort; + hiName = lib.toUpper productShort; + vmoptsName = loName + + lib.optionalString stdenv.hostPlatform.is64bit "64" + + ".vmoptions"; in with stdenv; lib.makeOverridable mkDerivation (rec { inherit pname version src; + passthru.buildNumber = buildNumber; meta = args.meta // { mainProgram = pname; }; desktopItem = makeDesktopItem { name = pname; exec = pname; - comment = lib.replaceStrings ["\n"] [" "] meta.longDescription; + comment = lib.replaceStrings [ "\n" ] [ " " ] meta.longDescription; desktopName = product; genericName = meta.description; categories = [ "Development" ]; @@ -32,30 +57,30 @@ with stdenv; lib.makeOverridable mkDerivation (rec { nativeBuildInputs = [ makeWrapper patchelf unzip ]; postPatch = '' - get_file_size() { - local fname="$1" - echo $(ls -l $fname | cut -d ' ' -f5) - } - - munge_size_hack() { - local fname="$1" - local size="$2" - strip $fname - truncate --size=$size $fname - } - - rm -rf jbr - - interpreter=$(echo ${stdenv.cc.libc}/lib/ld-linux*.so.2) - if [[ "${stdenv.hostPlatform.system}" == "x86_64-linux" && -e bin/fsnotifier64 ]]; then - target_size=$(get_file_size bin/fsnotifier64) - patchelf --set-interpreter "$interpreter" bin/fsnotifier64 - munge_size_hack bin/fsnotifier64 $target_size - else - target_size=$(get_file_size bin/fsnotifier) - patchelf --set-interpreter "$interpreter" bin/fsnotifier - munge_size_hack bin/fsnotifier $target_size - fi + get_file_size() { + local fname="$1" + echo $(ls -l $fname | cut -d ' ' -f5) + } + + munge_size_hack() { + local fname="$1" + local size="$2" + strip $fname + truncate --size=$size $fname + } + + rm -rf jbr + + interpreter=$(echo ${stdenv.cc.libc}/lib/ld-linux*.so.2) + if [[ "${stdenv.hostPlatform.system}" == "x86_64-linux" && -e bin/fsnotifier64 ]]; then + target_size=$(get_file_size bin/fsnotifier64) + patchelf --set-interpreter "$interpreter" bin/fsnotifier64 + munge_size_hack bin/fsnotifier64 $target_size + else + target_size=$(get_file_size bin/fsnotifier) + patchelf --set-interpreter "$interpreter" bin/fsnotifier + munge_size_hack bin/fsnotifier $target_size + fi ''; installPhase = '' diff --git a/pkgs/applications/editors/jetbrains/plugins/default.nix b/pkgs/applications/editors/jetbrains/plugins/default.nix new file mode 100644 index 000000000000000..e2ed92e96a54595 --- /dev/null +++ b/pkgs/applications/editors/jetbrains/plugins/default.nix @@ -0,0 +1,114 @@ +{ fetchurl +, fetchzip +, lib +, stdenv +, callPackage +, autoPatchelfHook +}: + +let + pluginsJson = builtins.fromJSON (builtins.readFile ./plugins.json); + specialPluginsInfo = callPackage ./specialPlugins.nix { }; + fetchPluginSrc = url: hash: + let + isJar = lib.hasSuffix ".jar" url; + fetcher = if isJar then fetchurl else fetchzip; + in + fetcher { + executable = isJar; + inherit url hash; + }; + files = builtins.mapAttrs (key: value: fetchPluginSrc key value) pluginsJson.files; + ids = builtins.attrNames pluginsJson.plugins; + + mkPlugin = id: file: + if !specialPluginsInfo ? "${id}" + then files."${file}" + else + stdenv.mkDerivation ({ + name = "jetbrains-plugin-${id}"; + installPhase = "mkdir $out && cp -r . $out"; + src = files."${file}"; + } // specialPluginsInfo."${id}"); + + selectFile = id: ide: build: + if !builtins.elem ide pluginsJson.plugins."${id}".compatible then + throw "Plugin with id ${id} does not support IDE ${ide}" + else if !pluginsJson.plugins."${id}".builds ? "${build}" then + throw "Jetbrains IDEs with build ${build} are not in nixpkgs. Try update_plugins.py with --with-build?" + else if pluginsJson.plugins."${id}".builds."${build}" == null then + throw "Plugin with id ${id} does not support build ${build}" + else + pluginsJson.plugins."${id}".builds."${build}"; + + byId = builtins.listToAttrs + (map + (id: { + name = id; + value = ide: build: mkPlugin id (selectFile id ide build); + }) + ids); + + byName = builtins.listToAttrs + (map + (id: { + name = pluginsJson.plugins."${id}".name; + value = byId."${id}"; + }) + ids); + + +in +rec { + # Only use if you know what youre doing + raw = { inherit files byId byName; }; + + addPlugins = ide: unprocessedPlugins: + let + + processPlugin = plugin: + if lib.isDerivation plugin then plugin else + if byId ? "${plugin}" then byId."${plugin}" ide.pname ide.buildNumber else + if byName ? "${plugin}" then byName."${plugin}" ide.pname ide.buildNumber else + throw "Could not resolve plugin ${plugin}"; + + plugins = map processPlugin unprocessedPlugins; + + in + stdenv.mkDerivation rec { + pname = meta.mainProgram + "-with-plugins"; + version = ide.version; + src = ide; + dontInstall = true; + dontFixup = true; + passthru.plugins = plugins ++ (ide.plugins or [ ]); + newPlugins = plugins; + disallowedReferences = [ ide ]; + nativeBuildInputs = [ autoPatchelfHook ] ++ (ide.nativeBuildInputs or [ ]); + buildInputs = ide.buildInputs or [ ]; + + inherit (ide) meta; + + buildPhase = + let + pluginCmdsLines = map (plugin: "ln -s ${plugin} \"$out\"/${meta.mainProgram}/plugins/${baseNameOf plugin}") plugins; + pluginCmds = builtins.concatStringsSep "\n" pluginCmdsLines; + extraBuildPhase = rec { + clion = '' + sed "s|${ide}|$out|" -i $out/bin/.clion-wrapped + autoPatchelf $out/clion/bin + ''; + }; + in + '' + cp -r ${ide} $out + chmod +w -R $out + IFS=' ' read -ra pluginArray <<< "$newPlugins" + for plugin in "''${pluginArray[@]}" + do + ln -s "$plugin" -t $out/${meta.mainProgram}/plugins/ + done + sed "s|${ide.outPath}|$out|" -i $out/bin/${meta.mainProgram} + '' + (extraBuildPhase."${ide.meta.mainProgram}" or ""); + }; +} diff --git a/pkgs/applications/editors/jetbrains/plugins/plugins.json b/pkgs/applications/editors/jetbrains/plugins/plugins.json new file mode 100644 index 000000000000000..1f93b6b0a5351c7 --- /dev/null +++ b/pkgs/applications/editors/jetbrains/plugins/plugins.json @@ -0,0 +1,390 @@ +{ + "plugins": { + "164": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/164/208284/IdeaVim-1.11.1.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip" + }, + "name": "ideavim" + }, + "631": { + "compatible": [ + "idea-ultimate" + ], + "builds": { + "231.8109.175": "https://plugins.jetbrains.com/files/631/312688/python-231.8109.175.zip" + }, + "name": "python" + }, + "6954": { + "compatible": [ + "idea-community", + "idea-ultimate" + ], + "builds": { + "231.8109.175": null + }, + "name": "kotlin" + }, + "6981": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": null, + "223.8836.42": "https://plugins.jetbrains.com/files/6981/306558/ini-223.8836.46.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/6981/306558/ini-223.8836.46.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/6981/306558/ini-223.8836.46.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/6981/316323/ini-231.8109.217.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/6981/316323/ini-231.8109.217.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/6981/316323/ini-231.8109.217.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/6981/316323/ini-231.8109.217.zip" + }, + "name": "ini" + }, + "7322": { + "compatible": [ + "datagrip", + "goland", + "idea-community", + "rider" + ], + "builds": { + "223.8836.53": "https://plugins.jetbrains.com/files/7322/300704/python-ce-223.8836.26.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/7322/300704/python-ce-223.8836.26.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/7322/311381/python-ce-231.8109.144.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/7322/311381/python-ce-231.8109.144.zip" + }, + "name": "python-community-edition" + }, + "8182": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/8182/277560/intellij-rust-0.4.186.5143-222.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/8182/318408/intellij-rust-0.4.192.5324-223.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/8182/318408/intellij-rust-0.4.192.5324-223.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/8182/318408/intellij-rust-0.4.192.5324-223.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/8182/318409/intellij-rust-0.4.192.5324-231.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/8182/318409/intellij-rust-0.4.192.5324-231.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/8182/318409/intellij-rust-0.4.192.5324-231.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/8182/318409/intellij-rust-0.4.192.5324-231.zip" + }, + "name": "rust" + }, + "8182-beta": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": null, + "223.8836.42": "https://plugins.jetbrains.com/files/8182/323147/intellij-rust-0.4.193.5343-223-beta.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/8182/323147/intellij-rust-0.4.193.5343-223-beta.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/8182/323147/intellij-rust-0.4.193.5343-223-beta.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/8182/323148/intellij-rust-0.4.193.5343-231-beta.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/8182/323148/intellij-rust-0.4.193.5343-231-beta.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/8182/323148/intellij-rust-0.4.193.5343-231-beta.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/8182/323148/intellij-rust-0.4.193.5343-231-beta.zip" + }, + "name": "rust-beta" + }, + "8554": { + "compatible": [ + "goland", + "idea-community", + "idea-ultimate", + "pycharm-community", + "pycharm-professional", + "ruby-mine", + "webstorm" + ], + "builds": { + "223.8836.56": "https://plugins.jetbrains.com/files/8554/295623/featuresTrainer-223.8836.10.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/8554/308384/featuresTrainer-231.8109.93.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/8554/308384/featuresTrainer-231.8109.93.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/8554/308384/featuresTrainer-231.8109.93.zip" + }, + "name": "ide-features-trainer" + }, + "8607": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip" + }, + "name": "nixidea" + }, + "9568": { + "compatible": [ + "idea-ultimate" + ], + "builds": { + "231.8109.175": "https://plugins.jetbrains.com/files/9568/312687/go-plugin-231.8109.175.zip" + }, + "name": "go" + }, + "10037": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/10037/298746/CSVEditor-3.1.0-222.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/10037/298744/CSVEditor-3.1.0-223.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/10037/298744/CSVEditor-3.1.0-223.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/10037/298744/CSVEditor-3.1.0-223.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/10037/298745/CSVEditor-3.1.0-231.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/10037/298745/CSVEditor-3.1.0-231.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/10037/298745/CSVEditor-3.1.0-231.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/10037/298745/CSVEditor-3.1.0-231.zip" + }, + "name": "csv-editor" + }, + "12559": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": null, + "223.8836.42": "https://plugins.jetbrains.com/files/12559/257029/keymap-eclipse-223.7571.125.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/12559/257029/keymap-eclipse-223.7571.125.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/12559/257029/keymap-eclipse-223.7571.125.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/12559/307825/keymap-eclipse-231.8109.91.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/12559/307825/keymap-eclipse-231.8109.91.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/12559/307825/keymap-eclipse-231.8109.91.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/12559/307825/keymap-eclipse-231.8109.91.zip" + }, + "name": "eclipse-keymap" + }, + "13017": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": null, + "223.8836.42": "https://plugins.jetbrains.com/files/13017/257030/keymap-visualStudio-223.7571.125.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/13017/257030/keymap-visualStudio-223.7571.125.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/13017/257030/keymap-visualStudio-223.7571.125.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/13017/307831/keymap-visualStudio-231.8109.91.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/13017/307831/keymap-visualStudio-231.8109.91.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/13017/307831/keymap-visualStudio-231.8109.91.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/13017/307831/keymap-visualStudio-231.8109.91.zip" + }, + "name": "visual-studio-keymap" + }, + "14059": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "223.8836.42": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "223.8836.53": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "223.8836.56": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "231.8109.163": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "231.8109.174": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "231.8109.175": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar", + "231.8109.197": "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar" + }, + "name": "darcula-pitch-black" + }, + "17718": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip" + }, + "name": "github-copilot" + }, + "18444": { + "compatible": [ + "clion", + "datagrip", + "goland", + "idea-community", + "idea-ultimate", + "mps", + "phpstorm", + "pycharm-community", + "pycharm-professional", + "rider", + "ruby-mine", + "webstorm" + ], + "builds": { + "222.3345.1295": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "223.8836.42": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "223.8836.53": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "223.8836.56": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "231.8109.163": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "231.8109.174": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "231.8109.175": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip", + "231.8109.197": "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip" + }, + "name": "netbeans-6-5-keymap" + } + }, + "files": { + "https://plugins.jetbrains.com/files/10037/298744/CSVEditor-3.1.0-223.zip": "sha256-/QrbqWNYbuLUMYDTDT0zivvHKdvVCosDDCLPOTx3XgA=", + "https://plugins.jetbrains.com/files/10037/298745/CSVEditor-3.1.0-231.zip": "sha256-wQ6gm+f+cqed8kt71N1c7Y/8owLLKaw8/1dvf5QevLk=", + "https://plugins.jetbrains.com/files/10037/298746/CSVEditor-3.1.0-222.zip": "sha256-+nKSPGTw23H12DBhK3Xa7FCvROKa48WMsukt1NQ1YGw=", + "https://plugins.jetbrains.com/files/12559/257029/keymap-eclipse-223.7571.125.zip": "sha256-0hMn8Qt+xJjB9HnYz7OMw8xmI0FxDFy+lYfXHURhTKY=", + "https://plugins.jetbrains.com/files/12559/307825/keymap-eclipse-231.8109.91.zip": "sha256-8jUsRK4evNMzjuWQIjIMrvQ0sIXPoY1C/buu1nod5X8=", + "https://plugins.jetbrains.com/files/13017/257030/keymap-visualStudio-223.7571.125.zip": "sha256-YiJALivO1a+I4bCtZEv68PZ21Vydk5UW6gAgErj28DQ=", + "https://plugins.jetbrains.com/files/13017/307831/keymap-visualStudio-231.8109.91.zip": "sha256-b/SFrQX+pIV/R/Dd72EjqbbRgaSgppe3kv4aSxWr//Y=", + "https://plugins.jetbrains.com/files/14059/82616/darcula-pitch-black.jar": "sha256-eXInfAqY3yEZRXCAuv3KGldM1pNKEioNwPB0rIGgJFw=", + "https://plugins.jetbrains.com/files/164/208284/IdeaVim-1.11.1.zip": "sha256-XxO3WUKYjxb0F/BT2i76P8bEPFL9reURNefzgIJ4yC0=", + "https://plugins.jetbrains.com/files/164/275091/IdeaVim-2.1.0.zip": "sha256-2dM/r79XT+1MHDeRAUnZw6WO3dmw7MZfx9alHmBqMk0=", + "https://plugins.jetbrains.com/files/17718/313933/github-copilot-intellij-1.2.5.2507.zip": "sha256-AZ8qKwI2OGBVd/0ulFAElm+Al9N3Ea5MGm+cMPAYHn4=", + "https://plugins.jetbrains.com/files/18444/165585/NetBeans6.5Keymap.zip": "sha256-KrzZTKZMQqoEMw+vDUv2jjs0EX0leaPBkU8H/ecq/oI=", + "https://plugins.jetbrains.com/files/631/312688/python-231.8109.175.zip": "sha256-e++OZuEPJ1NCKOsrcA/Oe6kL2y8sz3FIL2EoES3tR4Q=", + "https://plugins.jetbrains.com/files/6981/306558/ini-223.8836.46.zip": "sha256-8WOH8G/Lt5uFJFtbQIMuwuOidt2+drqT8gBtcLZuwpI=", + "https://plugins.jetbrains.com/files/6981/316323/ini-231.8109.217.zip": "sha256-anBogqu3bCuarcVIfi9m94jWcKEu8xnKtn+8ZFAa6tE=", + "https://plugins.jetbrains.com/files/7322/300704/python-ce-223.8836.26.zip": "sha256-mBWl5hwBtbjAfHCELgVk0gSJy2NChXvRC9+kVKXRhps=", + "https://plugins.jetbrains.com/files/7322/311381/python-ce-231.8109.144.zip": "sha256-eVz6THB5+amPrhF+VM4Yls2UySBbYO1DX6Watj94xg4=", + "https://plugins.jetbrains.com/files/8182/277560/intellij-rust-0.4.186.5143-222.zip": "sha256-8jdoyE+vWpalqDKHxs/uNPgu+Qe6Kb+0CjvJ0IA4I04=", + "https://plugins.jetbrains.com/files/8182/318408/intellij-rust-0.4.192.5324-223.zip": "sha256-8vVDReURiVVd12akCjqfJNzM3YVN7pAr7wdyKAHMt1o=", + "https://plugins.jetbrains.com/files/8182/318409/intellij-rust-0.4.192.5324-231.zip": "sha256-XUFH0bj/HI34eI2mQgkB2eeidXgOnt7rNh7B4Un5nNw=", + "https://plugins.jetbrains.com/files/8182/323147/intellij-rust-0.4.193.5343-223-beta.zip": "sha256-xruXR/kelzfPJg9+c/f79WnqAmdw4sGT7i3AbipKJMc=", + "https://plugins.jetbrains.com/files/8182/323148/intellij-rust-0.4.193.5343-231-beta.zip": "sha256-fC1t4x4BlERjkFSBJEYZNlIhLSU1wT9qifKE6Foqwkw=", + "https://plugins.jetbrains.com/files/8554/295623/featuresTrainer-223.8836.10.zip": "sha256-Jp2cy+fcbBk9ghBo0zjJUrAJA1Jvm2NK/x0ee+eQBoI=", + "https://plugins.jetbrains.com/files/8554/308384/featuresTrainer-231.8109.93.zip": "sha256-S5fcPHu73eerylw4RTBniFNbbEsOpY95fTGRADebvqU=", + "https://plugins.jetbrains.com/files/8607/318851/NixIDEA-0.4.0.9.zip": "sha256-byShwSfnAG8kXhoNu7CfOwvy4Viav784NT0UmzKY6hQ=", + "https://plugins.jetbrains.com/files/9568/312687/go-plugin-231.8109.175.zip": "sha256-Mxi5sKjCoD8lKKeSOteC4IAT7ekrr6fXb6qcfNbLeeg=" + } +} diff --git a/pkgs/applications/editors/jetbrains/plugins/specialPlugins.nix b/pkgs/applications/editors/jetbrains/plugins/specialPlugins.nix new file mode 100644 index 000000000000000..5d04debc7b08ab9 --- /dev/null +++ b/pkgs/applications/editors/jetbrains/plugins/specialPlugins.nix @@ -0,0 +1,63 @@ +{ delve, autoPatchelfHook, stdenv, lib, glibc, gcc-unwrapped }: +# This is a list of plugins that need special treatment. For example, the go plugin (id is 9568) comes with delve, a +# debugger, but that needs various linking fixes. The changes here replace it with the system one. +{ + "631" = { + # Python + nativeBuildInputs = [ autoPatchelfHook ]; + buildInputs = [ stdenv.cc.cc.lib ]; + }; + "7322" = { + # Python community edition + nativeBuildInputs = [ autoPatchelfHook ]; + buildInputs = [ stdenv.cc.cc.lib ]; + }; + "8182" = { + # Rust + nativeBuildInputs = [ autoPatchelfHook ]; + buildInputs = [ stdenv.cc.cc.lib ]; + buildPhase = '' + runHook preBuild + chmod +x -R bin + runHook postBuild + ''; + }; + "9568" = { + # Go + buildInputs = [ delve ]; + buildPhase = + let + arch = (if stdenv.isLinux then "linux" else "mac") + (if stdenv.isAarch64 then "arm" else ""); + in '' + runHook preBuild + ln -sf ${delve}/bin/dlv lib/dlv/${arch}/dlv + runHook postBuild + ''; + }; + "17718" = { + # Github Copilot + # Modified version of https://github.com/ktor/nixos/commit/35f4071faab696b2a4d86643726c9dd3e4293964 + buildPhase = '' + agent="copilot-agent/bin/copilot-agent-linux" + orig_size=$(stat --printf=%s $agent) + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $agent + patchelf --set-rpath ${lib.makeLibraryPath [glibc gcc-unwrapped]} $agent + chmod +x $agent + new_size=$(stat --printf=%s $agent) + var_skip=20 + var_select=22 + shift_by=$(($new_size-$orig_size)) + function fix_offset { + # $1 = name of variable to adjust + location=$(grep -obUam1 "$1" $agent | cut -d: -f1) + location=$(expr $location + $var_skip) + value=$(dd if=$agent iflag=count_bytes,skip_bytes skip=$location \ + bs=1 count=$var_select status=none) + value=$(expr $shift_by + $value) + echo -n $value | dd of=$agent bs=1 seek=$location conv=notrunc + } + fix_offset PAYLOAD_POSITION + fix_offset PRELUDE_POSITION + ''; + }; +} diff --git a/pkgs/applications/editors/jetbrains/plugins/update_plugins.py b/pkgs/applications/editors/jetbrains/plugins/update_plugins.py new file mode 100755 index 000000000000000..698bea9ff2773ae --- /dev/null +++ b/pkgs/applications/editors/jetbrains/plugins/update_plugins.py @@ -0,0 +1,385 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 python3.pkgs.requests nix.out + +from json import load, dumps +from pathlib import Path +from requests import get +from subprocess import run +from argparse import ArgumentParser + +# Token priorities for version checking +# From https://github.com/JetBrains/intellij-community/blob/94f40c5d77f60af16550f6f78d481aaff8deaca4/platform/util-rt/src/com/intellij/util/text/VersionComparatorUtil.java#L50 +TOKENS = { + "snap": 10, "snapshot": 10, + "m": 20, + "eap": 25, "pre": 25, "preview": 25, + "alpha": 30, "a": 30, + "beta": 40, "betta": 40, "b": 40, + "rc": 50, + "sp": 70, + "rel": 80, "release": 80, "r": 80, "final": 80 +} +SNAPSHOT_VALUE = 99999 +PLUGINS_FILE = Path(__file__).parent.joinpath("plugins.json").resolve() +IDES_FILE = Path(__file__).parent.joinpath("../versions.json").resolve() +# The plugin compatibility system uses a different naming scheme to the ide update system. +# These dicts convert between them +FRIENDLY_TO_PLUGIN = { + "clion": "CLION", + "datagrip": "DBE", + "goland": "GOLAND", + "idea-community": "IDEA_COMMUNITY", + "idea-ultimate": "IDEA", + "mps": "MPS", + "phpstorm": "PHPSTORM", + "pycharm-community": "PYCHARM_COMMUNITY", + "pycharm-professional": "PYCHARM", + "rider": "RIDER", + "ruby-mine": "RUBYMINE", + "webstorm": "WEBSTORM" +} +PLUGIN_TO_FRIENDLY = {j: i for i, j in FRIENDLY_TO_PLUGIN.items()} + + +def tokenize_stream(stream): + for item in stream: + if item in TOKENS: + yield TOKENS[item], 0 + elif item.isalpha(): + for char in item: + yield 90, ord(char) - 96 + elif item.isdigit(): + yield 100, int(item) + + +def split(version_string: str): + prev_type = None + block = "" + for char in version_string: + + if char.isdigit(): + cur_type = "number" + elif char.isalpha(): + cur_type = "letter" + else: + cur_type = "other" + + if cur_type != prev_type and block: + yield block.lower() + block = "" + + if cur_type in ("letter", "number"): + block += char + + prev_type = cur_type + + if block: + yield block + + +def tokenize_string(version_string: str): + return list(tokenize_stream(split(version_string))) + + +def pick_newest(ver1: str, ver2: str) -> str: + if ver1 is None or ver1 == ver2: + return ver2 + + if ver2 is None: + return ver1 + + presort = [tokenize_string(ver1), tokenize_string(ver2)] + postsort = sorted(presort) + if presort == postsort: + return ver2 + else: + return ver1 + + +def is_build_older(ver1: str, ver2: str) -> int: + ver1 = [int(i) for i in ver1.replace("*", str(SNAPSHOT_VALUE)).split(".")] + ver2 = [int(i) for i in ver2.replace("*", str(SNAPSHOT_VALUE)).split(".")] + + for i in range(min(len(ver1), len(ver2))): + if ver1[i] == ver2[i] and ver1[i] == SNAPSHOT_VALUE: + return 0 + if ver1[i] == SNAPSHOT_VALUE: + return 1 + if ver2[i] == SNAPSHOT_VALUE: + return -1 + result = ver1[i] - ver2[i] + if result != 0: + return result + + return len(ver1) - len(ver2) + + +def is_compatible(build, since, until) -> bool: + return (not since or is_build_older(since, build) < 0) and (not until or 0 < is_build_older(until, build)) + + +def get_newest_compatible(pid: str, build: str, plugin_infos: dict, quiet: bool) -> [None, str]: + newest_ver = None + newest_index = None + for index, info in enumerate(plugin_infos): + if pick_newest(newest_ver, info["version"]) != newest_ver and \ + is_compatible(build, info["since"], info["until"]): + newest_ver = info["version"] + newest_index = index + + if newest_ver is not None: + return "https://plugins.jetbrains.com/files/" + plugin_infos[newest_index]["file"] + else: + if not quiet: + print(f"WARNING: Could not find version of plugin {pid} compatible with build {build}") + return None + + +def flatten(main_list: list[list]) -> list: + return [item for sublist in main_list for item in sublist] + + +def get_compatible_ides(pid: str) -> list[str]: + int_id = pid.split("-", 1)[0] + url = f"https://plugins.jetbrains.com/api/plugins/{int_id}/compatible-products" + result = get(url).json() + return sorted([PLUGIN_TO_FRIENDLY[i] for i in result if i in PLUGIN_TO_FRIENDLY]) + + +def id_to_name(pid: str, channel="") -> str: + channel_ext = "-" + channel if channel else "" + + resp = get("https://plugins.jetbrains.com/api/plugins/" + pid).json() + return resp["link"].split("-", 1)[1] + channel_ext + + +def sort_dict(to_sort: dict) -> dict: + return {i: to_sort[i] for i in sorted(to_sort.keys())} + + +def make_name_mapping(infos: dict) -> dict[str, str]: + return sort_dict({i: id_to_name(*i.split("-", 1)) for i in infos.keys()}) + + +def make_plugin_files(plugin_infos: dict, ide_versions: dict, quiet: bool, extra_builds: list[str]) -> dict: + result = {} + names = make_name_mapping(plugin_infos) + for pid in plugin_infos: + plugin_versions = { + "compatible": get_compatible_ides(pid), + "builds": {}, + "name": names[pid] + } + relevant_builds = [builds for ide, builds in ide_versions.items() if ide in plugin_versions["compatible"]] + [extra_builds] + relevant_builds = sorted(list(set(flatten(relevant_builds)))) # Flatten, remove duplicates and sort + for build in relevant_builds: + plugin_versions["builds"][build] = get_newest_compatible(pid, build, plugin_infos[pid], quiet) + result[pid] = plugin_versions + + return result + + +def get_old_file_hashes() -> dict[str, str]: + return load(open(PLUGINS_FILE))["files"] + + +def get_hash(url): + print(f"Downloading {url}") + args = ["nix-prefetch-url", url, "--print-path"] + if url.endswith(".zip"): + args.append("--unpack") + else: + args.append("--executable") + path_process = run(args, capture_output=True) + path = path_process.stdout.decode().split("\n")[1] + result = run(["nix", "--extra-experimental-features", "nix-command", "hash", "path", path], capture_output=True) + result_contents = result.stdout.decode()[:-1] + if not result_contents: + raise RuntimeError(result.stderr.decode()) + return result_contents + + +def print_file_diff(old, new): + added = new.copy() + removed = old.copy() + to_delete = [] + + for file in added: + if file in removed: + to_delete.append(file) + + for file in to_delete: + added.remove(file) + removed.remove(file) + + if removed: + print("\nRemoved:") + for file in removed: + print(" - " + file) + print() + + if added: + print("\nAdded:") + for file in added: + print(" + " + file) + print() + + +def get_file_hashes(file_list: list[str], refetch_all: bool) -> dict[str, str]: + old = {} if refetch_all else get_old_file_hashes() + print_file_diff(list(old.keys()), file_list) + + file_hashes = {} + for file in sorted(file_list): + if file in old: + file_hashes[file] = old[file] + else: + file_hashes[file] = get_hash(file) + return file_hashes + + +def get_args() -> tuple[list[str], list[str], bool, bool, bool, list[str]]: + parser = ArgumentParser( + description="Add/remove/update entries in plugins.json", + epilog="To update all plugins, run with no args.\n" + "To add a version of a plugin from a different channel, append -[channel] to the id.\n" + "The id of a plugin is the number before the name in the address of its page on https://plugins.jetbrains.com/" + ) + parser.add_argument("-r", "--refetch-all", action="store_true", + help="don't use previously collected hashes, redownload all") + parser.add_argument("-l", "--list", action="store_true", + help="list plugin ids") + parser.add_argument("-q", "--quiet", action="store_true", + help="suppress warnings about not being able to find compatible plugin versions") + parser.add_argument("-w", "--with-build", action="append", default=[], + help="append [builds] to the list of builds to fetch plugin versions for") + sub = parser.add_subparsers(dest="action") + sub.add_parser("add").add_argument("ids", type=str, nargs="+", help="plugin(s) to add") + sub.add_parser("remove").add_argument("ids", type=str, nargs="+", help="plugin(s) to remove") + + args = parser.parse_args() + add = [] + remove = [] + + if args.action == "add": + add = args.ids + elif args.action == "remove": + remove = args.ids + + return add, remove, args.refetch_all, args.list, args.quiet, args.with_build + + +def sort_ids(ids: list[str]) -> list[str]: + sortable_ids = [] + for pid in ids: + if "-" in pid: + split_pid = pid.split("-", 1) + sortable_ids.append((int(split_pid[0]), split_pid[1])) + else: + sortable_ids.append((int(pid), "")) + sorted_ids = sorted(sortable_ids) + return [(f"{i}-{j}" if j else str(i)) for i, j in sorted_ids] + + +def get_plugin_ids(add: list[str], remove: list[str]) -> list[str]: + ids = list(load(open(PLUGINS_FILE))["plugins"].keys()) + + for pid in add: + if pid in ids: + raise ValueError(f"ID {pid} already in JSON file") + ids.append(pid) + + for pid in remove: + try: + ids.remove(pid) + except ValueError: + raise ValueError(f"ID {pid} not in JSON file") + return sort_ids(ids) + + +def get_plugin_info(pid: str, channel: str) -> dict: + url = f"https://plugins.jetbrains.com/api/plugins/{pid}/updates?channel={channel}" + resp = get(url) + decoded = resp.json() + + if resp.status_code != 200: + print(f"Server gave non-200 code {resp.status_code} with message " + decoded["message"]) + exit(1) + + return decoded + + +def ids_to_infos(ids: list[str]) -> dict: + result = {} + for pid in ids: + + if "-" in pid: + int_id, channel = pid.split("-", 1) + else: + channel = "" + int_id = pid + + result[pid] = get_plugin_info(int_id, channel) + return result + + +def get_ide_versions() -> dict: + ide_data = load(open(IDES_FILE)) + result = {} + for platform in ide_data: + for product in ide_data[platform]: + + version = ide_data[platform][product]["build_number"] + if product not in result: + result[product] = [version] + elif version not in result[product]: + result[product].append(version) + + # Gateway isn't a normal IDE, so it doesn't use the same plugins system + del result["gateway"] + + return result + + +def get_file_names(plugins: dict[str, dict]) -> list[str]: + result = [] + for plugin_info in plugins.values(): + for url in plugin_info["builds"].values(): + if url is not None: + result.append(url) + + return list(set(result)) + + +def dump(obj, file): + file.write(dumps(obj, indent=2)) + file.write("\n") + + +def write_result(to_write): + dump(to_write, open(PLUGINS_FILE, "w")) + + +def main(): + add, remove, refetch_all, list_ids, quiet, extra_builds = get_args() + result = {} + + print("Fetching plugin info") + ids = get_plugin_ids(add, remove) + if list_ids: + print(*ids) + plugin_infos = ids_to_infos(ids) + + print("Working out which plugins need which files") + ide_versions = get_ide_versions() + result["plugins"] = make_plugin_files(plugin_infos, ide_versions, quiet, extra_builds) + + print("Getting file hashes") + file_list = get_file_names(result["plugins"]) + result["files"] = get_file_hashes(file_list, refetch_all) + + write_result(result) + + +if __name__ == '__main__': + main() diff --git a/pkgs/applications/editors/jetbrains/update.py b/pkgs/applications/editors/jetbrains/update_ides.py similarity index 100% rename from pkgs/applications/editors/jetbrains/update.py rename to pkgs/applications/editors/jetbrains/update_ides.py