[education/rkward] rkward: Move detection of R installation closer to the backend
Thomas Friedrichsmeier
null at kde.org
Sat Jun 8 23:21:01 BST 2024
Git commit a2d710d221806ec16721c70ba8f49326867b982b by Thomas Friedrichsmeier.
Committed on 08/06/2024 at 22:10.
Pushed by tfry into branch 'master'.
Move detection of R installation closer to the backend
M +0 -2 rkward/CMakeLists.txt
M +1 -1 rkward/dialogs/rksetupwizard.cpp
M +0 -61 rkward/main.cpp
M +1 -0 rkward/rbackend/CMakeLists.txt
M +59 -3 rkward/rbackend/rkfrontendtransmitter.cpp
M +3 -0 rkward/rbackend/rkfrontendtransmitter.h
M +0 -1 rkward/rbackend/rkrinterface.cpp
M +1 -1 rkward/rbackend/rksessionvars.h
https://invent.kde.org/education/rkward/-/commit/a2d710d221806ec16721c70ba8f49326867b982b
diff --git a/rkward/CMakeLists.txt b/rkward/CMakeLists.txt
index 1ab4e48b8..331e4e0b7 100644
--- a/rkward/CMakeLists.txt
+++ b/rkward/CMakeLists.txt
@@ -37,12 +37,10 @@ SET(RKWard_Lib_Sources
QT_ADD_RESOURCES(RKWard_Lib_Sources resources.qrc icons/icons.qrc)
# somehow the detected R paths from FindR.cmake do not get passed down automatically
-GET_DIRECTORY_PROPERTY(R_EXECUTABLE DIRECTORY rbackend DEFINITION R_EXECUTABLE)
GET_DIRECTORY_PROPERTY(R_SHAREDLIBDIR DIRECTORY rbackend LINK_DIRECTORIES)
LINK_DIRECTORIES(${R_SHAREDLIBDIR})
ADD_LIBRARY(rkward_lib STATIC ${RKWard_Lib_Sources})
-TARGET_COMPILE_DEFINITIONS(rkward_lib PUBLIC -DR_EXECUTABLE="${R_EXECUTABLE}")
TARGET_LINK_LIBRARIES(rkward_lib windows ${RKWARD_ADDLIBS} agents dialogs plugin settings dataeditor core scriptbackends rbackend misc KDAB::kdsingleapplication KF6::WindowSystem Qt6::Widgets KF6::XmlGui)
SET(RKWard_App_Sources
diff --git a/rkward/dialogs/rksetupwizard.cpp b/rkward/dialogs/rksetupwizard.cpp
index 88295fbdd..c1610073d 100644
--- a/rkward/dialogs/rksetupwizard.cpp
+++ b/rkward/dialogs/rksetupwizard.cpp
@@ -112,7 +112,7 @@ public:
h->addWidget(rstatus_icon);
h->addWidget(rstatus_label);
h->setStretch(1, 2);
- detail_button = new QPushButton(i18n("Show error details"));
+ detail_button = new QPushButton(i18n("Show problem details"));
connect(detail_button, &QPushButton::clicked, this, [this]() {
if (!backend_error.details.isEmpty()) {
// WORKAROUND for silly KMessageBox behavior. (still needed in KF6 6.3.0)
diff --git a/rkward/main.cpp b/rkward/main.cpp
index 8071a01b4..1933b5e26 100644
--- a/rkward/main.cpp
+++ b/rkward/main.cpp
@@ -61,8 +61,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include <QApplication>
#include <QUrl>
#include <QTime>
-#include <QSettings>
-#include <QStandardPaths>
#include <stdio.h>
#include <stdlib.h>
@@ -85,10 +83,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include "version.h"
-#ifndef R_EXECUTABLE
-#error config problem
-#endif
-
#ifdef Q_OS_WIN
# define PATH_VAR_SEP ';'
#else
@@ -142,32 +136,6 @@ void RKDebug (int flags, int level, const char *fmt, ...) {
}
}
-/** Check if the given path to R (or "auto") is executable, and fail with an appropriate message, otherwise. If "auto" is given as input, try to auto-locate an R installation at the standard
-installation path(s) for this platform. */
-QString resolveRSpecOrFail (QString input, const QString &message) {
- if (input == QLatin1String ("auto")) {
- QString ret = RKSessionVars::findRInstallations().value(0);
-
- if (ret.isNull() || !QFileInfo (ret).isExecutable()) {
- QMessageBox::critical(nullptr, i18n("Unable to detect R installation"), i18n("RKWard failed to detect an R installation on this system. Either R is not installed, or not at one of the standard installation locations. You can use the command line parameter '--r-executable <i>auto / PATH_TO_R</i>', or supply an rkward.ini file to specify a non-standard location."));
- exit (1);
- }
-
- RK_DEBUG (APP, DL_DEBUG, "Using auto-detected R at %s", qPrintable (ret));
- return ret;
- } else {
- if (QFileInfo (input).isExecutable ()) {
- return input;
- }
-
- // TODO, while fixing krazy2 warnings: KMessageBox layout for static messages is quirky in that it has squeezed caption, and does not allow resize -> Submit a patch.
- //KMessageBox::error (0, QString ("The R executable specified on the command line (%1) does not exist or is not executable.").arg (r_exe), "Specified R executable does not exist");
- QMessageBox::critical(nullptr, i18n("Specified R executable does not exist"), message);
- exit(1);
- }
- return QString(); // not reached
-}
-
#include <QWebEngineUrlScheme>
int main (int argc, char *argv[]) {
@@ -279,35 +247,6 @@ int main (int argc, char *argv[]) {
}
}
- // Look for R:
- //- command line parameter
- //- Specified in cfg file next to rkward executable
- //- compile-time default
- QString r_exe = args[RKCommandLineArgs::RExecutable].toString();
- if (!r_exe.isNull ()) {
- r_exe = resolveRSpecOrFail (r_exe, i18n ("The R executable specified on the command line (%1) does not exist or is not executable.", r_exe));
- RK_DEBUG (APP, DL_DEBUG, "Using R specified on command line");
- } else {
- QDir frontend_path = app.applicationDirPath ();
- QFileInfo rkward_ini_file (frontend_path.absoluteFilePath ("rkward.ini"));
- if (rkward_ini_file.isReadable ()) {
- QSettings rkward_ini (rkward_ini_file.absoluteFilePath (), QSettings::IniFormat);
- r_exe = rkward_ini.value ("R executable").toString ();
- if (!r_exe.isNull ()) {
- if (QDir::isRelativePath (r_exe) && r_exe != QStringLiteral ("auto")) {
- r_exe = frontend_path.absoluteFilePath (r_exe);
- }
- r_exe = resolveRSpecOrFail (r_exe, i18n ("The R executable (%1) specified in the rkward.ini file (%2) does not exist or is not executable.", r_exe, rkward_ini_file.absoluteFilePath ()));
- }
- RK_DEBUG (APP, DL_DEBUG, "Using R as configured in config file %s", qPrintable (rkward_ini_file.absoluteFilePath ()));
- }
- if (r_exe.isNull ()) {
- r_exe = resolveRSpecOrFail (R_EXECUTABLE, i18n ("The R executable specified at compile time (%1) does not exist or is not executable. Probably the installation of R has moved. You can use the command line parameter '--r-executable <i>auto / PATH_TO_R</i>', or supply an rkward.ini file to specify the new location.", QString (R_EXECUTABLE)));
- RK_DEBUG (APP, DL_DEBUG, "Using R as configured at compile time");
- }
- }
- RKSessionVars::r_binary = r_exe;
-
if (app.isSessionRestored ()) {
kRestoreMainWindows<RKWardMainWindow>(); // well, whatever this is supposed to do -> TODO
} else {
diff --git a/rkward/rbackend/CMakeLists.txt b/rkward/rbackend/CMakeLists.txt
index 2c6ff0480..be7004d2e 100644
--- a/rkward/rbackend/CMakeLists.txt
+++ b/rkward/rbackend/CMakeLists.txt
@@ -44,6 +44,7 @@ SET (
)
ADD_LIBRARY(rbackend STATIC ${rbackend_frontend_SRCS} ${rbackend_shared_SRCS})
+TARGET_COMPILE_DEFINITIONS(rbackend PUBLIC -DR_EXECUTABLE="${R_EXECUTABLE}")
TARGET_LINK_LIBRARIES(rbackend rkgraphicsdevice.frontend Qt6::Widgets KF6::TextEditor KF6::WindowSystem)
ADD_DEFINITIONS (-DRKWARD_BACKEND_PATH="${KDE_INSTALL_FULL_LIBEXECDIR}")
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index 9f6d2ce21..10a80d371 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -25,6 +25,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include <QStandardPaths>
#include <QElapsedTimer>
#include <QTemporaryDir>
+#include <QSettings>
#include "../version.h"
#include "../debug.h"
@@ -107,10 +108,65 @@ QString localeDir () {
return QFileInfo (file.left (file.size() - relpath.size ())).absolutePath ();
}
+/** Check if the given path to R (or "auto") is executable, and fail with an appropriate message, otherwise. If "auto" is given as input, try to auto-locate an R installation at the standard
+installation path(s) for this platform. */
+QString RKFrontendTransmitter::resolveRSpecOrFail(QString input) {
+ if (input == QLatin1String("auto")) {
+ QString ret = RKSessionVars::findRInstallations().value(0);
+
+ if (ret.isNull() || !QFileInfo(ret).isExecutable()) {
+ handleTransmissionError(i18n("RKWard failed to detect an R installation on this system. Either R is not installed, or not at one of the standard installation locations."));
+ }
+ RK_DEBUG (APP, DL_DEBUG, "Using auto-detected R at %s", qPrintable (ret));
+ return ret;
+ }
+
+ if (!QFileInfo(input).isExecutable()) {
+ handleTransmissionError(i18n("The configured R installation at <b>%1</b> does not exist or is not an executable.", input));
+ }
+ return input;
+}
+
+void RKFrontendTransmitter::detectAndCheckRBinary() {
+ if (!RKSessionVars::RBinary().isEmpty()) return;
+
+ // Look for R:
+ //- command line parameter
+ //- Specified in cfg file next to rkward executable
+ //- compile-time default
+ QString r_exe = RKCommandLineArgs::get(RKCommandLineArgs::RExecutable).toString();
+ if (!r_exe.isEmpty()) {
+ RK_DEBUG(APP, DL_DEBUG, "Using R as specified on command line");
+ } else {
+ QDir frontend_path = qApp->applicationDirPath();
+ QFileInfo rkward_ini_file(frontend_path.absoluteFilePath("rkward.ini"));
+ if (rkward_ini_file.isReadable()) {
+ QSettings rkward_ini(rkward_ini_file.absoluteFilePath(), QSettings::IniFormat);
+ r_exe = rkward_ini.value("R executable").toString ();
+ if (!r_exe.isNull()) {
+ if (QDir::isRelativePath(r_exe) && r_exe != QStringLiteral("auto")) {
+ r_exe = frontend_path.absoluteFilePath (r_exe);
+ }
+ }
+ RK_DEBUG(APP, DL_DEBUG, "Using R as configured in config file %s", qPrintable (rkward_ini_file.absoluteFilePath ()));
+ } else {
+ RK_DEBUG(APP, DL_DEBUG, "Using R as configured at compile time");
+ r_exe = R_EXECUTABLE;
+ }
+ }
+ if (r_exe.isEmpty()) {
+ RK_DEBUG(APP, DL_DEBUG, "Falling back to auto-detection of R binary");
+ r_exe = "auto";
+ }
+
+ RKSessionVars::r_binary = resolveRSpecOrFail(r_exe);
+}
+
void RKFrontendTransmitter::run () {
RK_TRACE (RBACKEND);
quirkmode = RKCommandLineArgs::get(RKCommandLineArgs::QuirkMode).toBool();
+ detectAndCheckRBinary();
// start server
server = new QLocalServer (this);
@@ -320,9 +376,9 @@ void RKFrontendTransmitter::requestReceived (RBackendRequest* request) {
void RKFrontendTransmitter::backendExit (int exitcode) {
RK_TRACE (RBACKEND);
- if (!exitcode && token.isEmpty ()) handleTransmissionError (i18n ("The backend process could not be started. Please check your installation."));
- else if (token.isEmpty ()) handleTransmissionError (i18n ("The backend process failed to start with exit code %1, message: '%2'.", exitcode, QString::fromLocal8Bit(backend->readAllStandardError())));
- else handleTransmissionError (i18n ("Backend process has exited with code %1, message: '%2'.", exitcode, QString::fromLocal8Bit(backend->readAllStandardError())));
+ if (!exitcode && token.isEmpty()) handleTransmissionError(i18n("The backend process could not be started. Please check your installation."));
+ else if (token.isEmpty()) handleTransmissionError(i18n("The backend process failed to start with exit code %1, message: '%2'.", exitcode, QString::fromLocal8Bit(backend->readAllStandardError().replace('\n', "<br>"))));
+ else handleTransmissionError(i18n("Backend process has exited with code %1, message: '%2'.", exitcode, QString::fromLocal8Bit(backend->readAllStandardError().replace('\n', "<br>"))));
}
void RKFrontendTransmitter::writeRequest (RBackendRequest *request) {
diff --git a/rkward/rbackend/rkfrontendtransmitter.h b/rkward/rbackend/rkfrontendtransmitter.h
index eb0bd8b56..4c46d7fd7 100644
--- a/rkward/rbackend/rkfrontendtransmitter.h
+++ b/rkward/rbackend/rkfrontendtransmitter.h
@@ -44,6 +44,9 @@ private:
QLocalServer* server;
RKRBackendProtocolFrontend* frontend;
RKGraphicsDeviceFrontendTransmitter* rkd_transmitter;
+
+ QString resolveRSpecOrFail(QString input);
+ void detectAndCheckRBinary();
};
#endif
diff --git a/rkward/rbackend/rkrinterface.cpp b/rkward/rbackend/rkrinterface.cpp
index 67ad7607b..524a1112f 100644
--- a/rkward/rbackend/rkrinterface.cpp
+++ b/rkward/rbackend/rkrinterface.cpp
@@ -130,7 +130,6 @@ void RInterface::reportFatalError() {
RK_TRACE(RBACKEND);
RKErrorDialog::reportableErrorMessage(nullptr, backend_error.message, backend_error.details, backend_error.title, backend_error.id);
- backend_error = BackendError();
}
bool RInterface::backendIsIdle () {
diff --git a/rkward/rbackend/rksessionvars.h b/rkward/rbackend/rksessionvars.h
index 332fc0e63..eac63ce7c 100644
--- a/rkward/rbackend/rksessionvars.h
+++ b/rkward/rbackend/rksessionvars.h
@@ -52,7 +52,7 @@ private:
static RKParsedVersion r_version;
static QString r_version_string;
static QString appimagedir;
-friend int main(int, char**);
+friend class RKFrontendTransmitter;
friend class RKWardCoreTest;
friend class RKSetupWizard;
static QString r_binary;
More information about the rkward-tracker
mailing list