From d59fde4d85f05f16793703dfdc912d8072d9549e Mon Sep 17 00:00:00 2001 From: Krzysztof Saczuk Date: Sun, 8 Dec 2024 21:01:11 +0100 Subject: [PATCH] refactor(overlays): wrap JetBrains IDEs in derivation to avoid unnecessary re-builds --- .vscode/settings.json | 1 + modules/dev/ide.nix | 6 +- overlays/jetbrains/ides/default.nix | 112 +++++++++++++++---------- overlays/jetbrains/plugins/default.nix | 7 +- 4 files changed, 77 insertions(+), 49 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7872b55..7f75e04 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -139,6 +139,7 @@ "usbhid", "vesktop", "vfat", + "vmoptions", "vmopts", "waybar", "webstorm", diff --git a/modules/dev/ide.nix b/modules/dev/ide.nix index 6eb04db..43979ce 100644 --- a/modules/dev/ide.nix +++ b/modules/dev/ide.nix @@ -53,7 +53,7 @@ availableIdes = builtins.listToAttrs ( builtins.map (value: { - name = value.pname; + name = value.baseName or value.pname; inherit value; }) (with pkgs.jetbrains; [ @@ -99,13 +99,13 @@ (mkIDE webstorm {}) ]) ); - installedIDEs = builtins.map (name: availableIdes.${name} or availableIdes."${name}-with-plugins") cfg; + installedIDEs = builtins.map (name: availableIdes.${name}) cfg; in { options.modules.dev.ides = mkOption { description = "A list of JetBrains IDEs names to install"; example = ["rust-rover" "webstorm"]; default = []; - type = with types; listOf (enum (builtins.map (name: builtins.replaceStrings ["-with-plugins"] [""] name) (builtins.attrNames availableIdes))); + type = with types; listOf (enum (builtins.attrNames availableIdes)); }; config = mkIf (cfg != []) { diff --git a/overlays/jetbrains/ides/default.nix b/overlays/jetbrains/ides/default.nix index 944f221..97a5339 100644 --- a/overlays/jetbrains/ides/default.nix +++ b/overlays/jetbrains/ides/default.nix @@ -1,4 +1,19 @@ {lib, ...}: let + supportedIdes = [ + "clion" + "datagrip" + "dataspell" + "gateway" + "goland" + "idea-ultimate" + "mps" + "phpstorm" + "pycharm-professional" + "rider" + "ruby-mine" + "rust-rover" + "webstorm" + ]; in [ (final: prev: let inherit (lib) optionalString; @@ -20,8 +35,9 @@ in [ }; }) (final: prev: let - inherit (lib) optionalString optionalAttrs; + inherit (lib) optionalAttrs attrValues toLower; inherit (lib.my.mapper) toJavaProperties; + inherit (final) stdenv writeText; mkPatchedJetbrainsProductDerivation = name: { vmopts ? null, @@ -30,56 +46,66 @@ in [ plugins_path ? null, logs_path ? null, extraProperties ? null, - }: let - pkg = + } @ opts: let + shouldOverride = builtins.any (opt: opt != null) (attrValues opts); + ide = if !prev.jetbrains ? "${name}" then throw "JetBrains IDE with name ${name} is not in nixpkgs" else prev.jetbrains."${name}"; in - (pkg.override { - inherit vmopts; - }) - .overrideAttrs (prevAttrs: rec { - ideaPropertiesIDE = pkg.vmoptsIDE; - ideaPropertiesFile = - optionalString - (config_path != null || caches_path != null || plugins_path != null || logs_path != null || extraProperties != null) - ( - toJavaProperties "idea.properties" ({} + if shouldOverride + then + stdenv.mkDerivation rec { + inherit (ide) meta version buildNumber; + pname = meta.mainProgram + "-with-opts"; + baseName = meta.mainProgram; + src = ide; + dontInstall = true; + dontFixup = true; + nativeBuildInputs = ide.nativeBuildInputs or []; + buildInputs = ide.buildInputs or []; + + buildPhase = let + rootDir = + if stdenv.hostPlatform.isDarwin + then "Applications/${ide.product}.app/Contents" + else meta.mainProgram; + ideaPropertiesFile = toJavaProperties "${meta.mainProgram}" ({} // optionalAttrs (config_path != null) {"idea.config.path" = config_path;} // optionalAttrs (caches_path != null) {"idea.system.path" = caches_path;} // optionalAttrs (plugins_path != null) {"idea.plugins.path" = plugins_path;} // optionalAttrs (logs_path != null) {"idea.log.path" = logs_path;} - // optionalAttrs (extraProperties != null) extraProperties) - ); + // optionalAttrs (extraProperties != null) extraProperties); + + hiName = + if ide.vmoptsIDE == "WEBIDE" + then "WEBSTORM" + else ide.vmoptsIDE; + loName = toLower hiName; + vmoptsName = + loName + + lib.optionalString stdenv.hostPlatform.is64bit "64" + + ".vmoptions"; + vmoptsFile = lib.optionalString (vmopts != null) (writeText vmoptsName vmopts); + in '' + cp -r ${ide} $out + chmod +w -R $out + + printf "$(cat ${ideaPropertiesFile})\n\n# Default config\n\n$(cat "$out/${rootDir}/bin/idea.properties")" > "$out/${rootDir}/bin/idea.properties" + + substituteInPlace "$out/${rootDir}/bin/${loName}" \ + --replace-fail "${ide.vmoptsIDE}_VM_OPTIONS-'''" "${ide.vmoptsIDE}_VM_OPTIONS-'${vmoptsFile}'" + + sed "s|${ide.outPath}|$out|" \ + -i $(realpath $out/bin/${meta.mainProgram}) - installPhase = - builtins.replaceStrings - [''--set-default JDK_HOME "$jdk" \''] - [ - '' - --set-default ${ideaPropertiesIDE}_PROPERTIES "${ideaPropertiesFile}" \ - --set-default JDK_HOME "$jdk" \'' - ] - prevAttrs.installPhase; - }); - ides = [ - "clion" - "datagrip" - "dataspell" - "gateway" - "goland" - "idea-community" - "idea-ultimate" - "mps" - "phpstorm" - "pycharm-community" - "pycharm-professional" - "rider" - "ruby-mine" - "rust-rover" - "webstorm" - ]; + if test -f "$out/bin/${meta.mainProgram}-remote-dev-server"; then + sed "s|${ide.outPath}|$out|" \ + -i $(realpath $out/bin/${meta.mainProgram}-remote-dev-server) + fi + ''; + } + else ide; in { jetbrains = prev.jetbrains @@ -87,6 +113,6 @@ in [ inherit name; value = lib.makeOverridable (mkPatchedJetbrainsProductDerivation name) {}; }) - ides)); + supportedIdes)); }) ] diff --git a/overlays/jetbrains/plugins/default.nix b/overlays/jetbrains/plugins/default.nix index 92a4959..1e98a3b 100644 --- a/overlays/jetbrains/plugins/default.nix +++ b/overlays/jetbrains/plugins/default.nix @@ -70,7 +70,7 @@ in }) ids); in { - # Only use if you know what youre doing + # Only use if you know what you are doing raw = {inherit files byId byName ids;}; addPlugins = ide: unprocessedPlugins: let @@ -78,15 +78,16 @@ in if isDerivation plugin then plugin else if byId ? "${plugin}" - then byId."${plugin}" ide.pname ide.buildNumber + then byId."${plugin}" (ide.baseName or ide.pname) ide.buildNumber else if byName ? "${plugin}" - then byName."${plugin}" ide.pname ide.buildNumber + then byName."${plugin}" (ide.baseName or ide.pname) ide.buildNumber else throw "Could not resolve plugin ${plugin}"; plugins = map processPlugin unprocessedPlugins; in stdenv.mkDerivation rec { pname = meta.mainProgram + "-with-plugins"; + baseName = ide.baseName or meta.mainProgram; version = ide.version; src = ide; dontInstall = true;