<commit_before>/*
 * RSession.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * 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.
 *
 */

#define R_INTERNAL_FUNCTIONS
#include <r/session/RSession.hpp>

#include <iostream>

#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/Settings.hpp>
#include <core/system/System.hpp>
#include <core/FileSerializer.hpp>

#include <r/RExec.hpp>
#include <r/RUtil.hpp>
#include <r/RErrorCategory.hpp>
#include <r/ROptions.hpp>
#include <r/RSourceManager.hpp>
#include <r/RRoutines.hpp>
#include <r/RInterface.hpp>
#include <r/RFunctionHook.hpp>
#include <r/session/RConsoleActions.hpp>
#include <r/session/RConsoleHistory.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RGraphics.hpp>
#include <r/session/RDiscovery.hpp>

#include "RClientMetrics.hpp"
#include "RSessionState.hpp"
#include "REmbedded.hpp"

#include "graphics/RGraphicsUtils.hpp"
#include "graphics/RGraphicsDevice.hpp"
#include "graphics/RGraphicsPlotManager.hpp"

#include <Rembedded.h>
#include <R_ext/Utils.h>
#include <R_ext/Rdynload.h>
#include <R_ext/RStartup.h>
extern "C" SA_TYPE SaveAction;

#define CTXT_BROWSER 16 // from Defn.h

// get rid of windows TRUE and FALSE definitions
#undef TRUE
#undef FALSE

using namespace core ;

namespace r {
namespace session {

namespace {
   
// options
ROptions s_options;

// callbacks
RCallbacks s_callbacks;
   
// client-state path
FilePath s_clientStatePath;
   
// session state path
FilePath s_suspendedSessionPath ; 
   
// 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<void()> s_deferredDeserializationAction;
   
// have we completed our one-time initialization yet?
bool s_initialized = false;

// are in the middle of servicing a suspend request?
bool s_suspended = false;

// temporarily suppress output
bool s_suppressOuput = false;
class SuppressOutputInScope
{
public:
   SuppressOutputInScope() { s_suppressOuput = true; }
   ~SuppressOutputInScope() { s_suppressOuput = false; }
};

FilePath plotsStateFilePath()
{
   return s_options.scopedScratchPath.complete("plots");
}

FilePath rHistoryFilePath()
{
   std::string histFile = core::system::getenv("R_HISTFILE");
   boost::algorithm::trim(histFile);
   if (histFile.empty())
      histFile = ".Rhistory";

   return s_options.rHistoryDir().complete(histFile);
}

   
FilePath rSaveGlobalEnvironmentFilePath()
{
   FilePath rEnvironmentDir = s_options.rEnvironmentDir();
   return rEnvironmentDir.complete(".RData");
}

std::string createAliasedPath(const FilePath& filePath)
{
   return FilePath::createAliasedPath(filePath, s_options.userHomePath);
}
   
class SerializationCallbackScope : boost::noncopyable
{
public:
   SerializationCallbackScope(int action,
                              const FilePath& targetPath = FilePath())
   {
      s_callbacks.serialization(action, targetPath);
   }
   
   ~SerializationCallbackScope()
   {
      try {
         s_callbacks.serialization(kSerializationActionCompleted,
                                   FilePath());
      } catch(...) {}
   }
};
   

void reportDeferredDeserializationError(const Error& error)
{
   // log error
   LOG_ERROR(error);

   // report to user
   std::string errMsg = r::endUserErrorMessage(error);
   REprintf((errMsg + "\n").c_str());
}

void restoreWorkingState()
{
   // restore client metrics so the plot doesn't need to re-render
   client_metrics::restore(s_options.persistentState());

   // for migration we may need to restore from the suspended plots file
   FilePath plotsFile = plotsStateFilePath();
   if (!plotsFile.exists() && s_suspendedSessionPath.exists())
      plotsFile = s_suspendedSessionPath.childPath("plots");

   // restore the plots
   Error plotError = graphics::plotManager().restorePlotsState(plotsFile);
   if (plotError)
      reportDeferredDeserializationError(plotError);
}


void saveWorkingState(ClientStateCommitType commitType)
{
   using namespace r::session;

   // save client state (note we don't explicitly restore this
   // in restoreWorkingState, rather it is restored during
   // initialize() so that the client always has access to it when
   // for client_init)
   r::session::clientState().commit(commitType, s_clientStatePath);

   // save client metrics
   client_metrics::save(&(s_options.persistentState()));<commit_msg>move plots index file into the graphics subdirectory<commit_after>/*
 * RSession.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * 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.
 *
 */

#define R_INTERNAL_FUNCTIONS
#include <r/session/RSession.hpp>

#include <iostream>

#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/Settings.hpp>
#include <core/system/System.hpp>
#include <core/FileSerializer.hpp>

#include <r/RExec.hpp>
#include <r/RUtil.hpp>
#include <r/RErrorCategory.hpp>
#include <r/ROptions.hpp>
#include <r/RSourceManager.hpp>
#include <r/RRoutines.hpp>
#include <r/RInterface.hpp>
#include <r/RFunctionHook.hpp>
#include <r/session/RConsoleActions.hpp>
#include <r/session/RConsoleHistory.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RGraphics.hpp>
#include <r/session/RDiscovery.hpp>

#include "RClientMetrics.hpp"
#include "RSessionState.hpp"
#include "REmbedded.hpp"

#include "graphics/RGraphicsUtils.hpp"
#include "graphics/RGraphicsDevice.hpp"
#include "graphics/RGraphicsPlotManager.hpp"

#include <Rembedded.h>
#include <R_ext/Utils.h>
#include <R_ext/Rdynload.h>
#include <R_ext/RStartup.h>
extern "C" SA_TYPE SaveAction;

#define CTXT_BROWSER 16 // from Defn.h

// get rid of windows TRUE and FALSE definitions
#undef TRUE
#undef FALSE

using namespace core ;

namespace r {
namespace session {

namespace {
   
// options
ROptions s_options;

// callbacks
RCallbacks s_callbacks;
   
// client-state path
FilePath s_clientStatePath;
   
// session state path
FilePath s_suspendedSessionPath ; 
   
// 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<void()> s_deferredDeserializationAction;
   
// have we completed our one-time initialization yet?
bool s_initialized = false;

// are in the middle of servicing a suspend request?
bool s_suspended = false;

// temporarily suppress output
bool s_suppressOuput = false;
class SuppressOutputInScope
{
public:
   SuppressOutputInScope() { s_suppressOuput = true; }
   ~SuppressOutputInScope() { s_suppressOuput = false; }
};

FilePath plotsStateFilePath()
{
   return s_options.scopedScratchPath.complete("graphics/INDEX");
}

FilePath rHistoryFilePath()
{
   std::string histFile = core::system::getenv("R_HISTFILE");
   boost::algorithm::trim(histFile);
   if (histFile.empty())
      histFile = ".Rhistory";

   return s_options.rHistoryDir().complete(histFile);
}

   
FilePath rSaveGlobalEnvironmentFilePath()
{
   FilePath rEnvironmentDir = s_options.rEnvironmentDir();
   return rEnvironmentDir.complete(".RData");
}

std::string createAliasedPath(const FilePath& filePath)
{
   return FilePath::createAliasedPath(filePath, s_options.userHomePath);
}
   
class SerializationCallbackScope : boost::noncopyable
{
public:
   SerializationCallbackScope(int action,
                              const FilePath& targetPath = FilePath())
   {
      s_callbacks.serialization(action, targetPath);
   }
   
   ~SerializationCallbackScope()
   {
      try {
         s_callbacks.serialization(kSerializationActionCompleted,
                                   FilePath());
      } catch(...) {}
   }
};
   

void reportDeferredDeserializationError(const Error& error)
{
   // log error
   LOG_ERROR(error);

   // report to user
   std::string errMsg = r::endUserErrorMessage(error);
   REprintf((errMsg + "\n").c_str());
}

void restoreWorkingState()
{
   // restore client metrics so the plot doesn't need to re-render
   client_metrics::restore(s_options.persistentState());

   // for migration we may need to restore from the suspended plots file
   // or from the plots file contained in the root of the scopedScratchDir
   // TODO: eliminate these migration-oriented checks once we are
   // sufficiently clear of the migration date (7/11/2011)
   FilePath plotsFile = plotsStateFilePath();
   FilePath oldPlotsFile = s_options.scopedScratchPath.complete("plots");
   FilePath suspendedPlotsFile = s_suspendedSessionPath.childPath("plots");
   if (!plotsFile.exists())
   {
      // look in other potential locations for the file (migration)
      plotsFile = oldPlotsFile;
      if (!plotsFile.exists() && s_suspendedSessionPath.exists())
         plotsFile = suspendedPlotsFile;
   }
   else
   {
      // the first time we find the plots state file in the correct
      // location we can delete it from the old locations
      Error error = oldPlotsFile.removeIfExists();
      if (error)
         LOG_ERROR(error);
      error = suspendedPlotsFile.removeIfExists();
      if (error)
         LOG_ERROR(error);
   }

   // restore the plots
   Error plotError = graphics::plotManager().restorePlotsState(plotsFile);
   if (plotError)
      reportDeferredDeserializationError(plotError);
}


void saveWorkingState(ClientStateCommitType commitType)
{
   using namespace r::session;

   // save client state (note we don't explicitly restore this
   // in restoreWorkingState, rather it is restored during
   // initialize() so that the client always has access to it when
   // for client_init)
   r::session::clientState().commit(commitType, s_clientStatePath);

   // save client metrics
   client_metrics::save(&(s_options.persistentState()));
{'fraction_non_alphanumeric': 0.10661663768646472, 'fraction_numerical': 0.002653976388761783, 'mean_word_length': 4.159584513692162, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7366913', 'n_tokens_mistral': 3353, 'n_tokens_neox': 3251, 'n_words': 873}