Skip to content

Commit 9c9e6f0

Browse files
authored
rstudio: build as electron app, add darwin support (#362637)
2 parents 325307a + 889a85a commit 9c9e6f0

File tree

7 files changed

+396
-90
lines changed

7 files changed

+396
-90
lines changed

pkgs/applications/editors/rstudio/default.nix

Lines changed: 133 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
lib,
33
stdenv,
4+
runCommand,
45
fetchzip,
56
fetchFromGitHub,
67
replaceVars,
@@ -9,7 +10,7 @@
910
zlib,
1011
openssl,
1112
R,
12-
libsForQt5,
13+
fontconfig,
1314
quarto,
1415
libuuid,
1516
hunspellDicts,
@@ -21,16 +22,34 @@
2122
yaml-cpp,
2223
soci,
2324
sqlite,
25+
apple-sdk_11,
26+
xcbuild,
2427
nodejs,
28+
npmHooks,
29+
fetchNpmDeps,
2530
yarn,
2631
yarnConfigHook,
2732
fetchYarnDeps,
33+
zip,
34+
git,
35+
makeWrapper,
36+
electron_33,
2837
server ? false, # build server version
2938
pam,
3039
nixosTests,
3140
}:
3241

3342
let
43+
# Note: we shouldn't use the latest electron here, since the node-abi dependency might
44+
# need to be updated every time the latest electron gets a new abi version number
45+
electron = electron_33;
46+
47+
# unpack tarball containing electron's headers
48+
electron-headers = runCommand "electron-headers" { } ''
49+
mkdir -p $out
50+
tar -C $out --strip-components=1 -xvf ${electron.headers}
51+
'';
52+
3453
mathJaxSrc = fetchzip {
3554
url = "https://s3.amazonaws.com/rstudio-buildtools/mathjax-27.zip";
3655
hash = "sha256-J7SZK/9q3HcXTD7WFHxvh++ttuCd89Vc4SEBrUEU0AI=";
@@ -53,6 +72,14 @@ let
5372
d: !(lib.hasAttr "dictFileName" d && lib.elem d.dictFileName (map (d: d.dictFileName) largeDicts))
5473
) hunspellDictionaries;
5574
dictionaries = largeDicts ++ otherDicts;
75+
76+
# rstudio assumes quarto bundles pandoc into bin/tools/
77+
quartoWrapper = runCommand "quarto-wrapper" { } ''
78+
mkdir -p $out/bin/tools
79+
ln -s ${lib.getExe pandoc} $out/bin/tools/pandoc
80+
ln -s ${lib.getExe quarto} $out/bin/quarto
81+
ln -s ${quarto}/share $out/share
82+
'';
5683
in
5784
stdenv.mkDerivation rec {
5885
pname = "RStudio";
@@ -66,7 +93,7 @@ stdenv.mkDerivation rec {
6693
src = fetchFromGitHub {
6794
owner = "rstudio";
6895
repo = "rstudio";
69-
rev = "refs/tags/v${version}";
96+
tag = "v${version}";
7097
hash = "sha256-j258eW1MYQrB6kkpjyolXdNuwQ3zSWv9so4q0QLsZuw=";
7198
};
7299

@@ -78,9 +105,14 @@ stdenv.mkDerivation rec {
78105
nodejs
79106
yarn
80107
yarnConfigHook
108+
zip
109+
git
81110
]
111+
++ lib.optionals stdenv.hostPlatform.isDarwin [ xcbuild ]
82112
++ lib.optionals (!server) [
83-
libsForQt5.wrapQtAppsHook
113+
(nodejs.python.withPackages (ps: [ ps.setuptools ]))
114+
npmHooks.npmConfigHook
115+
makeWrapper
84116
];
85117

86118
buildInputs =
@@ -94,30 +126,30 @@ stdenv.mkDerivation rec {
94126
soci
95127
sqlite.dev
96128
]
129+
++ lib.optionals stdenv.hostPlatform.isDarwin [ apple-sdk_11 ]
97130
++ lib.optionals server [ pam ]
98-
++ lib.optionals (!server) [
99-
libsForQt5.qtbase
100-
libsForQt5.qtxmlpatterns
101-
libsForQt5.qtsensors
102-
libsForQt5.qtwebengine
103-
libsForQt5.qtwebchannel
104-
];
131+
++ lib.optionals (!server) [ fontconfig ];
105132

106133
cmakeFlags =
107134
[
108-
(lib.cmakeFeature "RSTUDIO_TARGET" (if server then "Server" else "Desktop"))
135+
(lib.cmakeFeature "RSTUDIO_TARGET" (if server then "Server" else "Electron"))
109136
(lib.cmakeBool "RSTUDIO_USE_SYSTEM_SOCI" true)
110137
(lib.cmakeBool "RSTUDIO_USE_SYSTEM_BOOST" true)
111138
(lib.cmakeBool "RSTUDIO_USE_SYSTEM_YAML_CPP" true)
112139
(lib.cmakeBool "RSTUDIO_DISABLE_CHECK_FOR_UPDATES" true)
113140
(lib.cmakeBool "QUARTO_ENABLED" true)
114-
(lib.cmakeFeature "CMAKE_INSTALL_PREFIX" "${placeholder "out"}/lib/rstudio")
141+
(lib.cmakeBool "RSTUDIO_CRASHPAD_ENABLED" false) # This is a NOOP except on x86_64-darwin
142+
(lib.cmakeFeature "CMAKE_INSTALL_PREFIX" (
143+
(placeholder "out") + (if stdenv.isDarwin then "/Applications" else "/lib/rstudio")
144+
))
115145
]
116146
++ lib.optionals (!server) [
117-
(lib.cmakeFeature "QT_QMAKE_EXECUTABLE" "${libsForQt5.qmake}/bin/qmake")
118-
(lib.cmakeBool "RSTUDIO_INSTALL_FREEDESKTOP" true)
147+
(lib.cmakeBool "RSTUDIO_INSTALL_FREEDESKTOP" stdenv.hostPlatform.isLinux)
119148
];
120149

150+
# on Darwin, cmake uses find_library to locate R instead of using the PATH
151+
env.NIX_LDFLAGS = "-L${R}/lib/R/lib";
152+
121153
patches = [
122154
# Hack RStudio to only use the input R and provided libclang.
123155
(replaceVars ./r-location.patch {
@@ -130,8 +162,10 @@ stdenv.mkDerivation rec {
130162
./fix-resources-path.patch
131163
./ignore-etc-os-release.patch
132164
./dont-yarn-install.patch
133-
./dont-assume-pandoc-in-quarto.patch
134165
./boost-1.86.patch
166+
./fix-darwin.patch
167+
# needed for rebuilding for later electron versions
168+
./update-nan-and-node-abi.patch
135169
];
136170

137171
postPatch = ''
@@ -151,6 +185,21 @@ stdenv.mkDerivation rec {
151185

152186
dontYarnInstallDeps = true; # will call manually in preConfigure
153187

188+
npmRoot = "src/node/desktop";
189+
190+
# don't build native modules with node headers
191+
npmFlags = [ "--ignore-scripts" ];
192+
193+
npmDeps = fetchNpmDeps {
194+
name = "rstudio-${version}-npm-deps";
195+
inherit src;
196+
patches = [ ./update-nan-and-node-abi.patch ];
197+
postPatch = "cd ${npmRoot}";
198+
hash = "sha256-CtHCN4sWeHNDd59TV/TgTC4d6h7X1Cl4E/aJkAfRk7g=";
199+
};
200+
201+
env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
202+
154203
preConfigure = ''
155204
# set up node_modules directory inside quarto so that panmirror can be built
156205
mkdir src/gwt/lib/quarto
@@ -170,35 +219,89 @@ stdenv.mkDerivation rec {
170219
done
171220
done
172221
173-
ln -s ${quarto} dependencies/quarto
222+
ln -s ${quartoWrapper} dependencies/quarto
174223
175224
# version in dependencies/common/install-mathjax
176225
ln -s ${mathJaxSrc} dependencies/mathjax-27
177226
178-
# version in CMakeGlobals.txt (PANDOC_VERSION)
179-
mkdir -p dependencies/pandoc/2.18
180-
ln -s ${lib.getBin pandoc}/bin/* dependencies/pandoc/2.18
181-
182-
# version in CMakeGlobals.txt (RSTUDIO_INSTALLED_NODE_VERSION)
183227
mkdir -p dependencies/common/node
228+
# node used by cmake
229+
# version in CMakeGlobals.txt (RSTUDIO_NODE_VERSION)
230+
ln -s ${nodejs} dependencies/common/node/18.18.2
231+
# node used at runtime
232+
# version in CMakeGlobals.txt (RSTUDIO_INSTALLED_NODE_VERSION)
184233
ln -s ${nodejs} dependencies/common/node/18.20.3
234+
235+
${lib.optionalString (!server) ''
236+
pushd $npmRoot
237+
238+
substituteInPlace package.json \
239+
--replace-fail "npm ci && " ""
240+
241+
# use electron's headers to make node-gyp compile against the electron ABI
242+
export npm_config_nodedir="${electron-headers}"
243+
244+
### override the detected electron version
245+
substituteInPlace node_modules/@electron-forge/core-utils/dist/electron-version.js \
246+
--replace-fail "return version" "return '${electron.version}'"
247+
248+
### create the electron archive to be used by electron-packager
249+
cp -r ${electron.dist} electron-dist
250+
chmod -R u+w electron-dist
251+
252+
pushd electron-dist
253+
zip -0Xqr ../electron.zip .
254+
popd
255+
256+
rm -r electron-dist
257+
258+
# force @electron/packager to use our electron instead of downloading it
259+
substituteInPlace node_modules/@electron/packager/src/index.js \
260+
--replace-fail "await this.getElectronZipPath(downloadOpts)" "'$(pwd)/electron.zip'"
261+
262+
# Work around known nan issue for electron_33 and above
263+
# https://github.com/nodejs/nan/issues/978
264+
substituteInPlace node_modules/nan/nan.h \
265+
--replace-fail '#include "nan_scriptorigin.h"' ""
266+
267+
# now that we patched everything, we still have to run the scripts we ignored with --ignore-scripts
268+
npm rebuild
269+
270+
popd
271+
''}
185272
'';
186273

187274
postInstall = ''
188275
mkdir -p $out/bin
189276
190-
${lib.optionalString server ''
277+
${lib.optionalString (server && stdenv.hostPlatform.isLinux) ''
191278
ln -s $out/lib/rstudio/bin/{crash-handler-proxy,postback,r-ldpath,rpostback,rserver,rserver-pam,rsession,rstudio-server} $out/bin
192279
''}
193280
194-
${lib.optionalString (!server) ''
195-
ln -s $out/lib/rstudio/bin/{diagnostics,rpostback,rstudio} $out/bin
281+
${lib.optionalString (!server && stdenv.hostPlatform.isLinux) ''
282+
# remove unneeded electron files, since we'll wrap the app with our own electron
283+
shopt -s extglob
284+
rm -r $out/lib/rstudio/!(locales|resources|resources.pak)
285+
286+
makeWrapper ${lib.getExe electron} "$out/bin/rstudio" \
287+
--add-flags "$out/lib/rstudio/resources/app/" \
288+
--set-default ELECTRON_FORCE_IS_PACKAGED 1 \
289+
--suffix PATH : ${lib.makeBinPath [ gnumake ]}
290+
291+
ln -s $out/lib/rstudio/resources/app/bin/{diagnostics,rpostback} $out/bin
196292
''}
197-
'';
198293
199-
qtWrapperArgs = lib.optionals (!server) [
200-
"--suffix PATH : ${lib.makeBinPath [ gnumake ]}"
201-
];
294+
${lib.optionalString (server && stdenv.hostPlatform.isDarwin) ''
295+
ln -s $out/Applications/RStudio.app/Contents/MacOS/{crash-handler-proxy,postback,r-ldpath,rpostback,rserver,rserver-pam,rsession,rstudio-server} $out/bin
296+
''}
297+
298+
${lib.optionalString (!server && stdenv.hostPlatform.isDarwin) ''
299+
# electron can't find its files if we use a symlink here
300+
makeWrapper $out/Applications/RStudio.app/Contents/MacOS/RStudio $out/bin/rstudio
301+
302+
ln -s $out/Applications/RStudio.app/Contents/Resources/app/bin/{diagnostics,rpostback} $out/bin
303+
''}
304+
'';
202305

203306
passthru = {
204307
inherit server;
@@ -208,15 +311,15 @@ stdenv.mkDerivation rec {
208311
};
209312

210313
meta = {
211-
broken = (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isAarch64);
212314
description = "Set of integrated tools for the R language";
213315
homepage = "https://www.rstudio.com/";
214316
license = lib.licenses.agpl3Only;
215317
maintainers = with lib.maintainers; [
216318
ciil
217319
cfhammill
320+
tomasajt
218321
];
219322
mainProgram = "rstudio" + lib.optionalString server "-server";
220-
platforms = lib.platforms.linux;
323+
platforms = lib.platforms.linux ++ lib.platforms.darwin;
221324
};
222325
}

pkgs/applications/editors/rstudio/dont-assume-pandoc-in-quarto.patch

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)