1{
2 stdenv,
3 lib,
4 copyDesktopItems,
5 makeDesktopItem,
6 unzip,
7 libsecret,
8 libXScrnSaver,
9 libxshmfence,
10 buildPackages,
11 at-spi2-atk,
12 autoPatchelfHook,
13 alsa-lib,
14 libgbm,
15 nss,
16 nspr,
17 xorg,
18 systemd,
19 fontconfig,
20 libdbusmenu,
21 glib,
22 buildFHSEnv,
23 wayland,
24 libglvnd,
25 libkrb5,
26 openssl,
27
28 # Populate passthru.tests
29 tests,
30
31 # needed to fix "Save as Root"
32 asar,
33 bash,
34
35 # Attributes inherit from specific versions
36 version,
37 vscodeVersion ? version,
38 src,
39 meta,
40 sourceRoot,
41 commandLineArgs,
42 executableName,
43 longName,
44 shortName,
45 pname,
46 libraryName ? "vscode",
47 iconName ? "vs${executableName}",
48 updateScript,
49 dontFixup ? false,
50 rev ? null,
51 vscodeServer ? null,
52 sourceExecutableName ? executableName,
53 useVSCodeRipgrep ? false,
54 ripgrep,
55 hasVsceSign ? false,
56 patchVSCodePath ? true,
57}:
58
59stdenv.mkDerivation (
60 finalAttrs:
61 let
62
63 # Vscode and variants allow for users to download and use extensions
64 # which often include the usage of pre-built binaries.
65 # This has been an on-going painpoint for many users, as
66 # a full extension update cycle has to be done through nixpkgs
67 # in order to create or update extensions.
68 # See: #83288 #91179 #73810 #41189
69 #
70 # buildFHSEnv allows for users to use the existing vscode
71 # extension tooling without significant pain.
72 fhs =
73 {
74 additionalPkgs ? pkgs: [ ],
75 }:
76 buildFHSEnv {
77 # also determines the name of the wrapped command
78 pname = executableName;
79 inherit version;
80
81 # additional libraries which are commonly needed for extensions
82 targetPkgs =
83 pkgs:
84 (with pkgs; [
85 # ld-linux-x86-64-linux.so.2 and others
86 glibc
87
88 # dotnet
89 curl
90 icu
91 libunwind
92 libuuid
93 lttng-ust
94 openssl
95 zlib
96
97 # mono
98 krb5
99 ])
100 ++ additionalPkgs pkgs;
101
102 extraBwrapArgs = [
103 "--bind-try /etc/nixos/ /etc/nixos/"
104 ];
105
106 # symlink shared assets, including icons and desktop entries
107 extraInstallCommands = ''
108 ln -s "${finalAttrs.finalPackage}/share" "$out/"
109 '';
110
111 runScript = "${finalAttrs.finalPackage}/bin/${executableName}";
112
113 # vscode likes to kill the parent so that the
114 # gui application isn't attached to the terminal session
115 dieWithParent = false;
116
117 passthru = {
118 inherit executableName;
119 inherit (finalAttrs.finalPackage) pname version; # for home-manager module
120 };
121
122 meta = meta // {
123 description = ''
124 Wrapped variant of ${pname} which launches in a FHS compatible environment.
125 Should allow for easy usage of extensions without nix-specific modifications.
126 '';
127 };
128 };
129 in
130 {
131
132 inherit
133 pname
134 version
135 src
136 sourceRoot
137 dontFixup
138 ;
139
140 passthru = {
141 inherit
142 executableName
143 longName
144 tests
145 updateScript
146 vscodeVersion
147 ;
148 fhs = fhs { };
149 fhsWithPackages = f: fhs { additionalPkgs = f; };
150 }
151 // lib.optionalAttrs (vscodeServer != null) {
152 inherit rev vscodeServer;
153 };
154
155 desktopItems = [
156 (makeDesktopItem {
157 name = executableName;
158 desktopName = longName;
159 comment = "Code Editing. Redefined.";
160 genericName = "Text Editor";
161 exec = "${executableName} %F";
162 icon = iconName;
163 startupNotify = true;
164 startupWMClass = shortName;
165 categories = [
166 "Utility"
167 "TextEditor"
168 "Development"
169 "IDE"
170 ];
171 keywords = [ "vscode" ];
172 actions.new-empty-window = {
173 name = "New Empty Window";
174 exec = "${executableName} --new-window %F";
175 icon = iconName;
176 };
177 })
178 (makeDesktopItem {
179 name = executableName + "-url-handler";
180 desktopName = longName + " - URL Handler";
181 comment = "Code Editing. Redefined.";
182 genericName = "Text Editor";
183 exec = executableName + " --open-url %U";
184 icon = iconName;
185 startupNotify = true;
186 startupWMClass = shortName;
187 categories = [
188 "Utility"
189 "TextEditor"
190 "Development"
191 "IDE"
192 ];
193 mimeTypes = [ "x-scheme-handler/${iconName}" ];
194 keywords = [ "vscode" ];
195 noDisplay = true;
196 })
197 ];
198
199 buildInputs = [
200 libsecret
201 libXScrnSaver
202 libxshmfence
203 ]
204 ++ lib.optionals (!stdenv.hostPlatform.isDarwin) [
205 alsa-lib
206 at-spi2-atk
207 libkrb5
208 libgbm
209 nss
210 nspr
211 systemd
212 xorg.libxkbfile
213 ];
214
215 runtimeDependencies = lib.optionals stdenv.hostPlatform.isLinux [
216 (lib.getLib systemd)
217 fontconfig.lib
218 libdbusmenu
219 wayland
220 libsecret
221 ];
222
223 nativeBuildInputs = [
224 unzip
225 ]
226 ++ lib.optionals stdenv.hostPlatform.isLinux [
227 autoPatchelfHook
228 asar
229 copyDesktopItems
230 # override doesn't preserve splicing https://github.com/NixOS/nixpkgs/issues/132651
231 # Has to use `makeShellWrapper` from `buildPackages` even though `makeShellWrapper` from the inputs is spliced because `propagatedBuildInputs` would pick the wrong one because of a different offset.
232 (buildPackages.wrapGAppsHook3.override { makeWrapper = buildPackages.makeShellWrapper; })
233 ];
234
235 dontBuild = true;
236 dontConfigure = true;
237 noDumpEnvVars = true;
238
239 stripExclude = lib.optional hasVsceSign [
240 # vsce-sign is a single executable application built with Node.js, and it becomes non-functional if stripped
241 "lib/vscode/resources/app/node_modules/@vscode/vsce-sign/bin/vsce-sign"
242 ];
243
244 installPhase = ''
245 runHook preInstall
246 ''
247 + (
248 if stdenv.hostPlatform.isDarwin then
249 ''
250 mkdir -p "$out/Applications/${longName}.app" "$out/bin"
251 cp -r ./* "$out/Applications/${longName}.app"
252 ln -s "$out/Applications/${longName}.app/Contents/Resources/app/bin/${sourceExecutableName}" "$out/bin/${executableName}"
253 ''
254 else
255 ''
256 mkdir -p "$out/lib/${libraryName}" "$out/bin"
257 cp -r ./* "$out/lib/${libraryName}"
258
259 ln -s "$out/lib/${libraryName}/bin/${sourceExecutableName}" "$out/bin/${executableName}"
260
261 # These are named vscode.png, vscode-insiders.png, etc to match the name in upstream *.deb packages.
262 mkdir -p "$out/share/pixmaps"
263 cp "$out/lib/${libraryName}/resources/app/resources/linux/code.png" "$out/share/pixmaps/${iconName}.png"
264
265 ''
266 + (lib.optionalString patchVSCodePath ''
267 # Override the previously determined VSCODE_PATH with the one we know to be correct
268 sed -i "/ELECTRON=/iVSCODE_PATH='$out/lib/${libraryName}'" "$out/bin/${executableName}"
269 grep -q "VSCODE_PATH='$out/lib/${libraryName}'" "$out/bin/${executableName}" # check if sed succeeded
270 '')
271 + ''
272
273 # Remove native encryption code, as it derives the key from the executable path which does not work for us.
274 # The credentials should be stored in a secure keychain already, so the benefit of this is questionable
275 # in the first place.
276 rm -rf $out/lib/${libraryName}/resources/app/node_modules/vscode-encrypt
277 ''
278 )
279 + ''
280 runHook postInstall
281 '';
282
283 preFixup = ''
284 gappsWrapperArgs+=(
285 ${
286 # we cannot use runtimeDependencies otherwise libdbusmenu do not work on kde
287 lib.optionalString stdenv.hostPlatform.isLinux
288 "--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ libdbusmenu ]}"
289 }
290 # Add gio to PATH so that moving files to the trash works when not using a desktop environment
291 --prefix PATH : ${glib.bin}/bin
292 --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}"
293 --add-flags ${lib.escapeShellArg commandLineArgs}
294 )
295 '';
296
297 # See https://github.com/NixOS/nixpkgs/issues/49643#issuecomment-873853897
298 # linux only because of https://github.com/NixOS/nixpkgs/issues/138729
299 postPatch =
300 lib.optionalString stdenv.hostPlatform.isLinux ''
301 # this is a fix for "save as root" functionality
302 packed="resources/app/node_modules.asar"
303 unpacked="resources/app/node_modules"
304 asar extract "$packed" "$unpacked"
305 substituteInPlace $unpacked/@vscode/sudo-prompt/index.js \
306 --replace "/usr/bin/pkexec" "/run/wrappers/bin/pkexec" \
307 --replace "/bin/bash" "${bash}/bin/bash"
308 rm -rf "$packed"
309
310 # without this symlink loading JsChardet, the library that is used for auto encoding detection when files.autoGuessEncoding is true,
311 # fails to load with: electron/js2c/renderer_init: Error: Cannot find module 'jschardet'
312 # and the window immediately closes which renders VSCode unusable
313 # see https://github.com/NixOS/nixpkgs/issues/152939 for full log
314 ln -rs "$unpacked" "$packed"
315 ''
316 + (
317 let
318 vscodeRipgrep =
319 if stdenv.hostPlatform.isDarwin then
320 if lib.versionAtLeast vscodeVersion "1.94.0" then
321 "Contents/Resources/app/node_modules/@vscode/ripgrep/bin/rg"
322 else
323 "Contents/Resources/app/node_modules.asar.unpacked/@vscode/ripgrep/bin/rg"
324 else
325 "resources/app/node_modules/@vscode/ripgrep/bin/rg";
326 in
327 if !useVSCodeRipgrep then
328 ''
329 rm ${vscodeRipgrep}
330 ln -s ${ripgrep}/bin/rg ${vscodeRipgrep}
331 ''
332 else
333 ''
334 chmod +x ${vscodeRipgrep}
335 ''
336 );
337
338 postFixup = lib.optionalString stdenv.hostPlatform.isLinux (
339 ''
340 patchelf \
341 --add-needed ${libglvnd}/lib/libGLESv2.so.2 \
342 --add-needed ${libglvnd}/lib/libGL.so.1 \
343 --add-needed ${libglvnd}/lib/libEGL.so.1 \
344 $out/lib/${libraryName}/${executableName}
345 ''
346 + (lib.optionalString hasVsceSign ''
347 patchelf \
348 --add-needed ${lib.getLib openssl}/lib/libssl.so \
349 $out/lib/vscode/resources/app/node_modules/@vscode/vsce-sign/bin/vsce-sign
350 '')
351 );
352
353 inherit meta;
354 }
355)