1{
2 fetchurl,
3 fetchzip,
4 lib,
5 stdenv,
6 callPackage,
7 autoPatchelfHook,
8 glib,
9 darwin,
10}:
11
12let
13 pluginsJson = builtins.fromJSON (builtins.readFile ./plugins.json);
14 specialPluginsInfo = callPackage ./specialPlugins.nix { };
15 fetchPluginSrc =
16 url: hash:
17 let
18 isJar = lib.hasSuffix ".jar" url;
19 fetcher = if isJar then fetchurl else fetchzip;
20 in
21 fetcher {
22 executable = isJar;
23 inherit url hash;
24 };
25 files = builtins.mapAttrs (key: value: fetchPluginSrc key value) pluginsJson.files;
26 ids = builtins.attrNames pluginsJson.plugins;
27
28 mkPlugin =
29 id: file:
30 if !specialPluginsInfo ? "${id}" then
31 files."${file}"
32 else
33 stdenv.mkDerivation (
34 {
35 name = "jetbrains-plugin-${id}";
36 installPhase = ''
37 runHook preInstall
38 mkdir -p $out && cp -r . $out
39 runHook postInstall
40 '';
41 src = files."${file}";
42 }
43 // specialPluginsInfo."${id}"
44 );
45
46 selectFile =
47 id: ide: build:
48 if !builtins.elem ide pluginsJson.plugins."${id}".compatible then
49 throw "Plugin with id ${id} does not support IDE ${ide}"
50 else if !pluginsJson.plugins."${id}".builds ? "${build}" then
51 throw "Jetbrains IDEs with build ${build} are not in nixpkgs. Try update_plugins.py with --with-build?"
52 else if pluginsJson.plugins."${id}".builds."${build}" == null then
53 throw "Plugin with id ${id} does not support build ${build}"
54 else
55 pluginsJson.plugins."${id}".builds."${build}";
56
57 byId = builtins.listToAttrs (
58 map (id: {
59 name = id;
60 value = ide: build: mkPlugin id (selectFile id ide build);
61 }) ids
62 );
63
64 byName = builtins.listToAttrs (
65 map (id: {
66 name = pluginsJson.plugins."${id}".name;
67 value = byId."${id}";
68 }) ids
69 );
70in
71{
72 # Only use if you know what youre doing
73 raw = { inherit files byId byName; };
74
75 tests = callPackage ./tests.nix { };
76
77 addPlugins =
78 ide: unprocessedPlugins:
79 let
80 processPlugin =
81 plugin:
82 if lib.isDerivation plugin then
83 plugin
84 else if byId ? "${plugin}" then
85 byId."${plugin}" ide.pname ide.buildNumber
86 else if byName ? "${plugin}" then
87 byName."${plugin}" ide.pname ide.buildNumber
88 else
89 throw "Could not resolve plugin ${plugin}";
90
91 plugins = map processPlugin unprocessedPlugins;
92 in
93 stdenv.mkDerivation rec {
94 pname = meta.mainProgram + "-with-plugins";
95 version = ide.version;
96 src = ide;
97 dontInstall = true;
98 dontStrip = true;
99 passthru.plugins = plugins ++ (ide.plugins or [ ]);
100 newPlugins = plugins;
101 disallowedReferences = [ ide ];
102 nativeBuildInputs =
103 (lib.optional stdenv.hostPlatform.isLinux autoPatchelfHook)
104 # The buildPhase hook rewrites the binary, which invaliates the code
105 # signature. Add the fixup hook to sign the output.
106 ++ (lib.optional stdenv.hostPlatform.isDarwin darwin.autoSignDarwinBinariesHook)
107 ++ (ide.nativeBuildInputs or [ ]);
108 buildInputs = lib.unique ((ide.buildInputs or [ ]) ++ [ glib ]);
109
110 inherit (ide) meta;
111
112 buildPhase =
113 let
114 appDir = lib.optionalString stdenv.hostPlatform.isDarwin "Applications/${lib.escapeShellArg ide.product}.app";
115 rootDir = if stdenv.hostPlatform.isDarwin then "${appDir}/Contents" else meta.mainProgram;
116 in
117 ''
118 cp -r ${ide} $out
119 chmod +w -R $out
120 rm -f $out/${rootDir}/plugins/plugin-classpath.txt
121
122 (
123 shopt -s nullglob
124
125 IFS=' ' read -ra pluginArray <<< "$newPlugins"
126 for plugin in "''${pluginArray[@]}"; do
127 pluginfiles=($plugin)
128 if [[ "$plugin" == *.jar ]]; then
129 # if the plugin contains a single jar file, link it directly into the plugins folder
130 ln -s "$plugin" $out/${rootDir}/plugins/
131 else
132 # otherwise link the plugin directory itself
133 ln -s "$plugin" -t $out/${rootDir}/plugins/
134 fi
135 done
136
137 for exe in $out/${rootDir}/bin/*; do
138 if [ -x "$exe" ] && ( file "$exe" | grep -q 'text' ); then
139 substituteInPlace "$exe" --replace-quiet '${ide}' $out
140 fi
141 done
142 )
143 '';
144 };
145}