/*
* RInit.cpp
*
* Copyright (C) 2009-18 by RStudio, PBC
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "REmbedded.hpp"
#include "RInit.hpp"
#include "RSuspend.hpp"
#include "RStdCallbacks.hpp"
#include "RRestartContext.hpp"
#include "graphics/RGraphicsDevice.hpp"
// constants for graphics scratch subdirectory
#define kGraphicsPath "graphics"
using namespace rstudio::core;
namespace rstudio {
namespace r {
namespace session {
namespace {
// is this R 3.0 or greater
bool s_isR3 = false;
// is this R 3.3 or greater
bool s_isR3_3 = false;
// function for deferred deserialization actions. this encapsulates parts of
// the initialization process that are potentially highly latent. this allows
// clients to bring their UI up and then receive an event indicating that the
// latent deserialization actions are taking place
boost::function s_deferredDeserializationAction;
void reportDeferredDeserializationError(const Error& error)
{
// log error
LOG_ERROR(error);
// report to user
std::string errMsg = r::endUserErrorMessage(error);
REprintf((errMsg + "\n").c_str());
}
std::string createAliasedPath(const FilePath& filePath)
{
return FilePath::createAliasedPath(filePath, utils::userHomePath());
}
Error restoreGlobalEnvFromFile(const std::string& path, std::string* pErrMessage)
{
r::exec::RFunction fn(".rs.restoreGlobalEnvFromFile");
fn.addParam(path);
return fn.call(pErrMessage);
}
void completeDeferredSessionInit(bool newSession)
{
// always cleanup any restart context here
restartContext().removeSessionState();
// call external hook
if (rCallbacks().deferredInit)
rCallbacks().deferredInit(newSession);
}
void deferredRestoreSuspendedSession(
const boost::function& deferredRestoreAction)
{
// notify client of serialization status
SerializationCallbackScope cb(kSerializationActionResumeSession);
// suppress interrupts which occur during restore
r::exec::IgnoreInterruptsScope ignoreInterrupts;
// suppress output which occurs during restore (packages can sometimes
// print messages to the console indicating they have conflicts -- the
// has already seen these messages and doesn't expect them now so
// we suppress them
utils::SuppressOutputInScope suppressOutput;
// restore action
Error error = deferredRestoreAction();
if (error)
reportDeferredDeserializationError(error);
// complete deferred init
completeDeferredSessionInit(false);
}
void deferredRestoreNewSession()
{
// restore the default global environment if there is one
FilePath globalEnvPath = utils::startupEnvironmentFilePath();
if (utils::restoreWorkspace() && globalEnvPath.exists())
{
// notify client of serialization status
SerializationCallbackScope cb(kSerializationActionLoadDefaultWorkspace,
globalEnvPath);
// ignore interrupts which occur during restoring of the global env
// the restoration will run to completion in any case and then the
// next thing the user does will be "interrupted" -- clearly not
// what they intended
r::exec::IgnoreInterruptsScope ignoreInterrupts;
std::string path = string_utils::utf8ToSystem(globalEnvPath.getAbsolutePath());
std::string aliasedPath = createAliasedPath(globalEnvPath);
std::string errMessage;
Error error = restoreGlobalEnvFromFile(path, &errMessage);
if (error)
{
::REprintf(
"WARNING: Failed to restore workspace from '%s' "
"(an internal error occurred)\n",
aliasedPath.c_str());
LOG_ERROR(error);
}
else if (!errMessage.empty())
{
std::stringstream ss;
ss