[rkward] /: Somewhat experimental: Auto-lazy-install RKWard R package

Thomas Friedrichsmeier null at kde.org
Mon Dec 30 13:43:13 GMT 2019


Git commit 8ecd26dcf2f42b748fcf2ca8259a8588e624e4d0 by Thomas Friedrichsmeier.
Committed on 30/12/2019 at 13:40.
Pushed by tfry into branch 'master'.

Somewhat experimental: Auto-lazy-install RKWard R package

This is so we can support switching to a different (compatible) R installation without re-installation of RKWard.
Needed on Mac, will be nice to have everywere.

Needs testing.

M  +1    -1    doc/rkward/man-rkward.1.docbook
M  +1    -0    rkward.kdev4
M  +18   -3    rkward/rbackend/rkrbackend.cpp
M  +12   -6    rkward/rbackend/rpackages/CMakeLists.txt
D  +0    -36   rkward/rbackend/rpackages/rpackage_install.cmake.in
M  +21   -1    rkward/rkward.cpp

https://commits.kde.org/rkward/8ecd26dcf2f42b748fcf2ca8259a8588e624e4d0

diff --git a/doc/rkward/man-rkward.1.docbook b/doc/rkward/man-rkward.1.docbook
index 8ff350ed..2b411c4a 100644
--- a/doc/rkward/man-rkward.1.docbook
+++ b/doc/rkward/man-rkward.1.docbook
@@ -80,7 +80,7 @@
 </varlistentry>
 <varlistentry>
 <term><option>--r-executable</option> <replaceable>command</replaceable></term>
-<listitem><para>In the case of several R installations, specify the installation to use, ⪚ <filename>/usr/bin/R</filename>. Note that the &rkward; R library must have been installed to this installation of R, or startup will fail.</para></listitem>
+<listitem><para>In the case of several R installations, specify the installation to use, ⪚ <filename>/usr/bin/R</filename>. You can also use the string <replaceable>"auto"</replaceable>, in  which case RKWard will try to find R at one of the known standard installation paths. <emphasis>NOTE</emphasis> that while RKWard will <emphasis>often</emphasis> work with newer versions of R, it will <emphasis>sometimes</emphasis> need to be re-compiled for that version, or it may be incompatible altogether.</para></listitem>
 </varlistentry>
 <varlistentry>
 <term><option>--reuse</option></term>
diff --git a/rkward.kdev4 b/rkward.kdev4
index e9cfb7f4..a2b625a0 100644
--- a/rkward.kdev4
+++ b/rkward.kdev4
@@ -1,3 +1,4 @@
 [Project]
+CreatedFrom=CMakeLists.txt
 Manager=KDevCMakeManager
 Name=rkward
diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index d255a9b6..a96439e7 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -2,7 +2,7 @@
                           rkrbackend  -  description
                              -------------------
     begin                : Sun Jul 25 2004
-    copyright            : (C) 2004 - 2013 by Thomas Friedrichsmeier
+    copyright            : (C) 2004 - 2019 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -1646,9 +1646,24 @@ void RKRBackend::initialize (const char *locale_dir) {
 
 	bool lib_load_fail = false;
 	bool sink_fail = false;
-	if (!runDirectCommand ("library (\"rkward\")\n")) lib_load_fail = true;
+	// Try to load rkward package. If that fails, or is the wrong version, try to install
+	// rkward package, then load again.
+	QString libloc = RKRBackendProtocolBackend::dataDir () + "/.rkward_packages/" + QString::number (r_version / 10);
+	QString versioncheck = QString ("stopifnot(.rk.app.version==\"%1\")\n").arg (RKWARD_VERSION);
+	QString command = "local({\n"
+	                  "  libloc <- " + RKRSharedFunctionality::quote (libloc) + "\n"
+	                  "  if (!dir.exists (libloc)) dir.create(libloc, recursive=TRUE)\n"
+	                  "  ok <- FALSE\n"
+	                  "  suppressWarnings (try ({library (\"rkward\", lib.loc=libloc); " + versioncheck + "; ok <- TRUE}))\n"
+					  "  if (!ok) {\n"
+					  "    suppressWarnings (try (detach(\"package:rkward\")))\n"
+					  "    install.packages(normalizePath(paste(libloc, \"..\", c (\"rkward.tgz\", \"rkwardtests.tgz\"), sep=\"/\")), lib=libloc, repos=NULL)\n"
+					  "    library (\"rkward\",  lib.loc=libloc)\n"
+					  "  }\n"
+					  "})\n";
+	if (!runDirectCommand (command)) lib_load_fail = true;
 	RK_setupGettext (locale_dir);	// must happen *after* package loading, since R will re-set it
-	if (!runDirectCommand (QString ("stopifnot(.rk.app.version==\"%1\")\n").arg (RKWARD_VERSION))) lib_load_fail = true;
+	if (!runDirectCommand (versioncheck)) lib_load_fail = true;
 	if (!runDirectCommand (".rk.fix.assignments ()\n")) sink_fail = true;
 
 // error/output sink and help browser
diff --git a/rkward/rbackend/rpackages/CMakeLists.txt b/rkward/rbackend/rpackages/CMakeLists.txt
index a503965f..0a6bd309 100644
--- a/rkward/rbackend/rpackages/CMakeLists.txt
+++ b/rkward/rbackend/rpackages/CMakeLists.txt
@@ -1,8 +1,14 @@
-INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}    )
+MACRO(createRpackage name)
+	FILE(GLOB_RECURSE rkwardfiles${name} LIST_DIRECTORIES true CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*")
+	MESSAGE(STATUS ${rkwardfiles${name}})
+	ADD_CUSTOM_COMMAND(OUTPUT ${name}.tgz
+		COMMAND ${CMAKE_COMMAND} -E tar "cfz" "${CMAKE_CURRENT_BINARY_DIR}/${name}.tgz" "${name}"
+		WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+		DEPENDS ${rkwardfiles${name}})
+ENDMACRO()
 
-CONFIGURE_FILE(
-	"${CMAKE_CURRENT_SOURCE_DIR}/rpackage_install.cmake.in"
-	"${CMAKE_CURRENT_BINARY_DIR}/rpackage_install.cmake"
-	@ONLY)
+createRpackage(rkward)
+createRpackage(rkwardtests)
+ADD_CUSTOM_TARGET(rpackages ALL DEPENDS rkward.tgz rkwardtests.tgz)
 
-INSTALL(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/rpackage_install.cmake -DDESTDIR=${DESTDIR} -DBUILD_TIMESTAMP=${BUILD_TIMESTAMP})
+INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/rkward.tgz" "${CMAKE_CURRENT_BINARY_DIR}/rkwardtests.tgz" DESTINATION ${DATA_INSTALL_DIR}/rkward/rpackages)
diff --git a/rkward/rbackend/rpackages/rpackage_install.cmake.in b/rkward/rbackend/rpackages/rpackage_install.cmake.in
deleted file mode 100644
index 476a45de..00000000
--- a/rkward/rbackend/rpackages/rpackage_install.cmake.in
+++ /dev/null
@@ -1,36 +0,0 @@
-SET(DESTDIR $ENV{DESTDIR})
-SET(BUILD_TIMESTAMP "@BUILD_TIMESTAMP@")
-
-MESSAGE(STATUS "Installing R support packages")
-
-IF(NOT ${BUILD_TIMESTAMP} EQUAL "")
-	SET (TIMESTAMPARG "--built-timestamp=${BUILD_TIMESTAMP}")
-ENDIF(NOT ${BUILD_TIMESTAMP} EQUAL "")
-
-IF(WIN32)
-	SET(R_LIBDIR @R_LIBDIR@)
-	IF(DESTDIR)
-		# strip drive letter
-		STRING(REGEX REPLACE "^.:." "" R_LIBDIR ${R_LIBDIR})
-		SET(R_LIBDIR "${DESTDIR}/${R_LIBDIR}")
-		FILE(MAKE_DIRECTORY "${R_LIBDIR}")
-	ENDIF(DESTDIR)
-	EXECUTE_PROCESS(
-		COMMAND @R_EXECUTABLE@ CMD INSTALL ${TIMESTAMPARG} -c -l ${R_LIBDIR} "@CMAKE_CURRENT_SOURCE_DIR@/rkward" "@CMAKE_CURRENT_SOURCE_DIR@/rkwardtests"
-		WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@"
-		RESULT_VARIABLE R_LIB_INSTALL_EXIT_CODE
-	)
-ELSE(WIN32)
-	EXECUTE_PROCESS(
-		COMMAND mkdir -p "@CMAKE_CURRENT_BINARY_DIR@/tmp" ${DESTDIR}/@R_LIBDIR@
-	)
-	EXECUTE_PROCESS(
-		COMMAND env TMPDIR="@CMAKE_CURRENT_BINARY_DIR@/tmp" @R_EXECUTABLE@ CMD INSTALL ${TIMESTAMPARG} -c -l ${DESTDIR}/@R_LIBDIR@ "@CMAKE_CURRENT_SOURCE_DIR@/rkward" "@CMAKE_CURRENT_SOURCE_DIR@/rkwardtests"
-		WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@"
-		RESULT_VARIABLE R_LIB_INSTALL_EXIT_CODE
-	)
-ENDIF(WIN32)
-
-IF(R_LIB_INSTALL_EXIT_CODE)
-	MESSAGE (SEND_ERROR "Failed to install R support libraries. Please make sure you have the required permissions.")
-ENDIF(R_LIB_INSTALL_EXIT_CODE)
diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index bb2f69cd..d32db527 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -360,9 +360,28 @@ void RKWardMainWindow::startR () {
 	RK_ASSERT (!RKGlobals::rInterface ());
 
 	// make sure our general purpose files directory exists
-	bool ok = QDir ().mkpath (RKSettingsModuleGeneral::filesPath());
+	QString packages_path = RKSettingsModuleGeneral::filesPath() + "/.rkward_packages";
+	bool ok = QDir ().mkpath (packages_path);
 	RK_ASSERT (ok);
 
+	// Copy RKWard R source packages to general  purpose files directory (if still needed).
+	// This may look redundant at first (since the package still needs to be installed from the
+	// backend. However, if frontend and backend are on different machines (eventually), only  the
+	// filesPath is shared between both.
+	QStringList packages;
+	packages << "rkward.tgz" << "rkwardtests.tgz";
+	for (int i = 0; i < packages.size (); ++i) {
+		QString package = QDir (packages_path).absoluteFilePath (packages[i]);
+		if (RKSettingsModuleGeneral::rkwardVersionChanged ()) {
+			RK_DEBUG(APP, DL_INFO, "RKWard version changed. Discarding cached package at %s", qPrintable (package));
+			QFile::remove (package);
+		}
+		if (!QFileInfo (package).exists()) {
+			RK_DEBUG(APP, DL_INFO, "Copying rkward R source package to %s", qPrintable (package));
+			RK_ASSERT(QFile::copy (RKCommonFunctions::getRKWardDataDir () + "/rpackages/" + packages[i], package));
+		}
+	}
+
 	RKGlobals::rinter = new RInterface ();
 	new RObjectList ();
 
@@ -947,3 +966,4 @@ void RKWardMainWindow::setCaption (const QString &) {
 	KParts::MainWindow::setCaption (wcaption);
 }
 
+



More information about the rkward-tracker mailing list