Beispiel #1
0
bool isHTMLWidgetPath(const FilePath& filePath)
{
   // parent of parent must be session temp dir
   // (this is required because of the way we copy/restore
   // widget directories during suspend/resume)
   FilePath parentDir = filePath.parent();
   if (parentDir.parent() != module_context::tempDir())
      return false;

   // it is a widget!
   return true;
}
Beispiel #2
0
std::string detectBuildType(const FilePath& projectFilePath,
                            const RProjectBuildDefaults& buildDefaults,
                            RProjectConfig* pConfig)
{
   FilePath projectDir = projectFilePath.parent();
   if (r_util::isPackageDirectory(projectDir))
   {
      setBuildPackageDefaults("", buildDefaults ,pConfig);
   }
   else if (projectDir.childPath("pkg/DESCRIPTION").exists())
   {
      setBuildPackageDefaults("pkg", buildDefaults, pConfig);
   }
   else if (projectDir.childPath("Makefile").exists())
   {
      pConfig->buildType = kBuildTypeMakefile;
      pConfig->makefilePath = "";
   }
   else if (isWebsiteDirectory(projectDir))
   {
      pConfig->buildType = kBuildTypeWebsite;
      pConfig->websitePath = "";
   }
   else
   {
      pConfig->buildType = kBuildTypeNone;
   }

   return pConfig->buildType;
}
Beispiel #3
0
Error parseBibtexLog(const FilePath& logFilePath, LogEntries* pLogEntries)
{
   boost::regex re("^(.*)---line ([0-9]+) of file (.*)$");

   // get the lines
   std::vector<std::string> lines;
   Error error = ::core::readStringVectorFromFile(logFilePath, &lines, false);
   if (error)
      return error;

   // look for error messages
   for (std::vector<std::string>::const_iterator it = lines.begin();
        it != lines.end();
        it++)
   {
      boost::smatch match;
      if (regex_match(*it, match, re))
      {
         pLogEntries->push_back(
               LogEntry(
                     logFilePath,
                     (it - lines.begin()) + 1,
                     LogEntry::Error,
                     texFilePath(match[3], logFilePath.parent()),
                     boost::lexical_cast<int>(match[2]),
                     match[1]));
      }
   }

   return Success();
}
Error getSlideNavigationForFile(const json::JsonRpcRequest& request,
                               json::JsonRpcResponse* pResponse)
{
   // get param
   std::string file;
   Error error = json::readParam(request.params, 0, &file);
   if (error)
      return error;
   FilePath filePath = module_context::resolveAliasedPath(file);

   // read code
   std::string code;
   error = core::readStringFromFile(filePath,
                                    &code,
                                    string_utils::LineEndingPosix);
   if (error)
      return error;

   // get slide navigation
   json::Object slideNavigationJson;
   error = getSlideNavigation(code, filePath.parent(), &slideNavigationJson);
   if (error)
      return error;
   pResponse->setResult(slideNavigationJson);

   return Success();
}
Beispiel #5
0
void onFileChanged(FilePath sourceFilePath)
{
   // ignore file changes while Packrat is running
   if (s_runningPackratAction != PACKRAT_ACTION_NONE)
      return;
   
   // we only care about mutations to files in the Packrat library directory
   // (and packrat.lock)
   FilePath libraryPath = 
      projects::projectContext().directory().complete(kPackratLibPath);

   if (sourceFilePath.filename() == kPackratLockfile)
   {
      PACKRAT_TRACE("detected change to lockfile " << sourceFilePath);
      checkHashes(HASH_TYPE_LOCKFILE, HASH_STATE_OBSERVED, onLockfileUpdate);
   }
   else if (sourceFilePath.isWithin(libraryPath) && 
            (sourceFilePath.isDirectory() || 
             sourceFilePath.filename() == "DESCRIPTION"))
   {
      // ignore changes in the RStudio-managed manipulate and rstudio 
      // directories and the files within them
      if (sourceFilePath.filename() == "manipulate" ||
          sourceFilePath.filename() == "rstudio" ||
          sourceFilePath.parent().filename() == "manipulate" || 
          sourceFilePath.parent().filename() == "rstudio")
      {
         return;
      }
      PACKRAT_TRACE("detected change to library file " << sourceFilePath);
      checkHashes(HASH_TYPE_LIBRARY, HASH_STATE_OBSERVED, onLibraryUpdate);
   }
}
bool readPresentation(SlideDeck* pSlideDeck,
                      std::string* pSlides,
                      std::string* pInitActions,
                      std::string* pSlideActions,
                      std::map<std::string,std::string>* pVars,
                      std::string* pErrMsg)
{
   // look for slides and knit if we need to
   FilePath rmdFile = presentation::state::filePath();
   std::string ext = rmdFile.extensionLowerCase();
   if (rmdFile.exists() && (ext != ".md"))
   {
      if (!performKnit(rmdFile, pErrMsg))
         return false;
   }

   // look for slides markdown
   FilePath slidesFile = rmdFile.parent().childPath(rmdFile.stem() + ".md");
   if (!slidesFile.exists())
   {
      *pErrMsg = slidesFile.absolutePath() + " not found";
      return false;
   }

   // parse the slides
   Error error = pSlideDeck->readSlides(slidesFile);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = error.summary();
      return false;
   }

   // render the slides
   std::string revealConfig;
   error = presentation::renderSlides(*pSlideDeck,
                                      pSlides,
                                      &revealConfig,
                                      pInitActions,
                                      pSlideActions);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = error.summary();
      return false;
   }

   // build template variables
   std::map<std::string,std::string>& vars = *pVars;
   vars["title"] = pSlideDeck->title();
   vars["slides"] = *pSlides;
   vars["slides_css"] =  resourceFiles().get("presentation/slides.css");
   vars["r_highlight"] = resourceFiles().get("r_highlight.html");
   vars["reveal_config"] = revealConfig;
   vars["preamble"] = pSlideDeck->preamble();

   return true;
}
Beispiel #7
0
Error listFiles(const json::JsonRpcRequest& request, json::JsonRpcResponse* pResponse)
{
   // get args
   std::string path;
   bool monitor;
   Error error = json::readParams(request.params, &path, &monitor);
   if (error)
      return error;
   FilePath targetPath = module_context::resolveAliasedPath(path) ;

   json::Object result;
   
   // if this includes a request for monitoring
   core::json::Array jsonFiles;
   if (monitor)
   {
      // always stop existing if we have one
      s_filesListingMonitor.stop();

      // install a monitor only if we aren't already covered by the project monitor
      if (!session::projects::projectContext().isMonitoringDirectory(targetPath))
      {
         error = s_filesListingMonitor.start(targetPath, &jsonFiles);
         if (error)
            return error;
      }
      else
      {
         error = FilesListingMonitor::listFiles(targetPath, &jsonFiles);
         if (error)
            return error;
      }
   }
   else
   {
      error = FilesListingMonitor::listFiles(targetPath, &jsonFiles);
      if (error)
         return error;
   }

   result["files"] = jsonFiles;

   bool browseable = true;

#ifndef _WIN32
   // on *nix systems, see if browsing above this path is possible
   error = core::system::isFileReadable(targetPath.parent(), &browseable);
   if (error && !core::isPathNotFoundError(error))
      LOG_ERROR(error);
#endif

   result["is_parent_browseable"] = browseable;

   pResponse->setResult(result);
   return Success();
}
Error setChunkDefs(const std::string& docPath, const std::string& docId,
                   std::time_t docTime, const json::Array& newDefs)
{
   // create JSON object wrapping 
   json::Object chunkDefs;
   chunkDefs[kChunkDefs] = newDefs;
   chunkDefs[kChunkDocWriteTime] = static_cast<boost::int64_t>(docTime);

   // ensure we have a place to write the sidecar file
   FilePath defFile = chunkDefinitionsPath(docPath, docId, 
         notebookCtxId());

   // if there are no old chunk definitions and we aren't adding any new ones,
   // no work to do
   if (!defFile.exists() && newDefs.size() < 1) 
      return Success();

   // we're going to write something; make sure the parent folder exists
   Error error = defFile.parent().ensureDirectory();
   if (error)
      return error;

   // get the old set of chunk IDs so we can clean up any not in the new set 
   // of chunks
   std::vector<std::string> chunkIds;
   json::Value oldDefs;
   std::string oldContent;
   error = getChunkDefs(docPath, docId, notebookCtxId(), NULL, 
         &oldDefs);
   if (error)
      LOG_ERROR(error);
   else if (oldDefs.type() == json::ArrayType)
   {
      if (oldDefs.get_array() == newDefs) 
      {
         // definitions not changing; no work to do
         return Success();
      }
      cleanChunks(chunkCacheFolder(docPath, docId),
                  oldDefs.get_array(), newDefs);
   }

   std::ostringstream oss;
   json::write(chunkDefs, oss);

   error = writeStringToFile(defFile, oss.str());
   if (error)
   {
      LOG_ERROR(error);
      return error;
   }
   
   return Success();
}
Beispiel #9
0
bool isHTMLWidgetPath(const FilePath& filePath)
{
   // get the session temp dir real path; needed since the file path above is
   // also a real path--e.g. on OS X, it refers to /private/tmp rather than
   // /tmp 
   FilePath tempDir;
   Error error = core::system::realPath(module_context::tempDir(), &tempDir);
   if (error)
      LOG_ERROR(error);

   // parent of parent must be session temp dir
   // (this is required because of the way we copy/restore
   // widget directories during suspend/resume)
   FilePath parentDir = filePath.parent();
   if (parentDir.parent() != tempDir)
      return false;

   // it is a widget!
   return true;
}
Beispiel #10
0
	void FileDialog::setPath(const FilePath &path) {
		if(path.isDirectory()) {
			m_dir_path = path;
			m_edit_box->setText({});
		}
		else {
			m_dir_path = path.parent();
			m_edit_box->setText(toUTF32Checked(path.fileName()));
		}
		updateList();
		updateButtons();
	}
void Options::resolvePandocPath(const FilePath& resourcePath,
                                std::string* pPath)
{
   if (*pPath == kDefaultPandocPath)
   {
      FilePath path = resourcePath.parent().complete("MacOS/pandoc");
      *pPath = path.absolutePath();
   }
   else
   {
      resolvePath(resourcePath, pPath);
   }
}
Beispiel #12
0
// installation path
Error installPath(const std::string& relativeToExecutable,
                  const char * argv0,
                  FilePath* pInstallPath)
{
   // get executable path
   FilePath executablePath;
   Error error = system::executablePath(argv0, &executablePath);
   if (error)
      return error;

   // fully resolve installation path relative to executable
   FilePath installPath = executablePath.parent().complete(relativeToExecutable);
   return realPath(installPath.absolutePath(), pInstallPath);
}
inline Error initializeStreamDir(const FilePath& streamDir)
{
   Error error = streamDir.ensureDirectory();
   if (error)
      return error;
      
   error = changeFileMode(streamDir.parent(),
                          system::EveryoneReadWriteExecuteMode);
   if (error)
      return error;
      
   return changeFileMode(streamDir,
                         system::EveryoneReadWriteExecuteMode);
}
void Options::resolvePostbackPath(const FilePath& resourcePath,
                                  std::string* pPath)
{
   // On OSX we keep the postback scripts over in the MacOS directory
   // rather than in the Resources directory -- make this adjustment
   // when the default postback path has been passed
   if (*pPath == kDefaultPostbackPath)
   {
      FilePath path = resourcePath.parent().complete("MacOS/postback/rpostback");
      *pPath = path.absolutePath();
   }
   else
   {
      resolvePath(resourcePath, pPath);
   }
}
Beispiel #15
0
SEXP rs_pathInfo(SEXP pathSEXP)
{
   try
   {
      // validate
      if (r::sexp::length(pathSEXP) != 1)
      {
         throw r::exec::RErrorException(
                        "must pass a single file to get path info for");
      }

      std::string path;
      Error error = r::sexp::extract(pathSEXP, &path);
      if (error)
         throw r::exec::RErrorException(r::endUserErrorMessage(error));

      // resolve aliased path
      FilePath filePath = module_context::resolveAliasedPath(path);
      if (filePath.empty())
         throw r::exec::RErrorException("invalid path: " + path);

      // create path info vector (use json repsesentation to force convertion
      // to VECSXP rather than STRSXP)
      json::Object pathInfo;
      pathInfo["path"] = filePath.absolutePath();
      std::string parent = filePath.absolutePath();
      FilePath parentPath = filePath.parent();
      if (!parentPath.empty())
         parent = parentPath.absolutePath();
      pathInfo["directory"] = parent;
      pathInfo["name"] = filePath.filename();
      pathInfo["stem"] = filePath.stem();
      pathInfo["extension"] = filePath.extension();

      // return it
      r::sexp::Protect rProtect;
      return r::sexp::create(pathInfo, &rProtect);
   }
   catch(r::exec::RErrorException e)
   {
      r::exec::error(e.message());
   }
   CATCH_UNEXPECTED_EXCEPTION

   return R_NilValue;
}
Beispiel #16
0
Error getTerminalOptions(const json::JsonRpcRequest& request,
                         json::JsonRpcResponse* pResponse)
{
   json::Object optionsJson;

   FilePath terminalPath;

#if defined(_WIN32)

   // if we are using git bash then return its path
   if (git::isGitEnabled() && userSettings().vcsUseGitBash())
   {
      FilePath gitExePath = git::detectedGitExePath();
      if (!gitExePath.empty())
         terminalPath = gitExePath.parent().childPath("sh.exe");
   }

#elif defined(__APPLE__)

   // do nothing (we always launch Terminal.app)

#else

   // auto-detection (+ overridable by a setting)
   terminalPath = userSettings().vcsTerminalPath();
   if (terminalPath.empty())
      terminalPath = detectedTerminalPath();

#endif

   // append shell paths as appropriate
   std::string extraPathEntries;
   ammendShellPaths(&extraPathEntries);

   optionsJson["terminal_path"] = terminalPath.absolutePath();
   optionsJson["working_directory"] =
                  module_context::shellWorkingDirectory().absolutePath();
   optionsJson["extra_path_entries"] = extraPathEntries;
   pResponse->setResult(optionsJson);

   return Success();
}
Beispiel #17
0
Error forwardSearch(const FilePath& rootFile,
                    const json::Object& sourceLocation,
                    json::Value* pPdfLocation)
{
   // read params
   std::string file;
   int line, column;
   bool fromClick;
   Error error = json::readObject(sourceLocation,
                                  "file", &file,
                                  "line", &line,
                                  "column", &column,
                                  "from_click", &fromClick);
   if (error)
      return error;

   // determine input file
   FilePath inputFile = module_context::resolveAliasedPath(file);

   // determine pdf
   FilePath pdfFile = rootFile.parent().complete(rootFile.stem() + ".pdf");

   core::tex::Synctex synctex;
   if (synctex.parse(pdfFile))
   {
      core::tex::SourceLocation srcLoc(inputFile, line, column);
      applyForwardConcordance(rootFile, &srcLoc);

      core::tex::PdfLocation pdfLoc = synctex.forwardSearch(srcLoc);
      *pPdfLocation = toJson(pdfFile, pdfLoc, fromClick);
   }
   else
   {
      *pPdfLocation = json::Value();
   }

   return Success();
}
void runCrashHandler(const char* argv[])
{
   FilePath exePath;
   Error error = executablePath(nullptr, &exePath);
   if (error)
      LOG_ERROR(error);

   FilePath handlerPath;
   std::string crashpadHandlerPath = rstudio::core::system::getenv(kCrashpadHandlerEnvVar);
   if (!crashpadHandlerPath.empty())
      handlerPath = FilePath(crashpadHandlerPath);
   else
      handlerPath = exePath.parent().childPath("crashpad_handler");

   std::string handlerPathStr = handlerPath.absolutePath();
   const char* handlerExe = handlerPathStr.c_str();
   argv[0] = handlerExe;

   ::execvp(handlerExe, const_cast<char* const*>(argv));

   // if we get here, we failed to run the crash handler
   // log an error indicating why
   LOG_ERROR(systemError(errno, ERROR_LOCATION));
}
Beispiel #19
0
Error createSshKey(const json::JsonRpcRequest& request,
                      json::JsonRpcResponse* pResponse)
{
   std::string path, type, passphrase;
   bool overwrite;
   Error error = json::readObjectParam(request.params, 0,
                                       "path", &path,
                                       "type", &type,
                                       "passphrase", &passphrase,
                                       "overwrite", &overwrite);
   if (error)
      return error;

#ifdef RSTUDIO_SERVER
   // In server mode, passphrases are encrypted
   using namespace rstudio::core::system::crypto;
   error = rsaPrivateDecrypt(passphrase, &passphrase);
   if (error)
      return error;
#endif

   // resolve key path
   FilePath sshKeyPath = module_context::resolveAliasedPath(path);
   FilePath sshPublicKeyPath = sshKeyPath.parent().complete(
                                             sshKeyPath.stem() + ".pub");
   if (sshKeyPath.exists() || sshPublicKeyPath.exists())
   {
      if (!overwrite)
      {
         json::Object resultJson;
         resultJson["failed_key_exists"] = true;
         pResponse->setResult(resultJson);
         return Success();
      }
      else
      {
         Error error = sshKeyPath.removeIfExists();
         if (error)
            return error;
         error = sshPublicKeyPath.removeIfExists();
         if (error)
            return error;
      }
   }

   // compose a shell command to create the key
   shell_utils::ShellCommand cmd("ssh-keygen");

   // type
   cmd << "-t" << type;

   // passphrase (optional)
   cmd << "-N";
   if (!passphrase.empty())
      cmd << passphrase;
   else
      cmd << std::string("");

   // path
   cmd << "-f" << sshKeyPath;

   // process options
   core::system::ProcessOptions options;

   // detach the session so there is no terminal
#ifndef _WIN32
   options.detachSession = true;
#endif

   // customize the environment on Win32
#ifdef _WIN32
   core::system::Options childEnv;
   core::system::environment(&childEnv);

   // set HOME to USERPROFILE
   std::string userProfile = core::system::getenv(childEnv, "USERPROFILE");
   core::system::setenv(&childEnv, "HOME", userProfile);

   // add msys_ssh to path
   core::system::addToPath(&childEnv,
                           session::options().msysSshPath().absolutePath());

   options.environment = childEnv;
#endif

   // run it
   core::system::ProcessResult result;
   error = runCommand(shell_utils::sendStdErrToStdOut(cmd),
                      options,
                      &result);
   if (error)
      return error;

   // return exit code and output
   json::Object resultJson;
   resultJson["failed_key_exists"] = false;
   resultJson["exit_status"] = result.exitStatus;
   resultJson["output"] = result.stdOut;
   pResponse->setResult(resultJson);
   return Success();
}
Beispiel #20
0
core::ProgramStatus Options::read(int argc, char * const argv[])
{
   using namespace boost::program_options ;
   
   // compute the resource path
   FilePath resourcePath;
   Error error = core::system::installPath("..", argc, argv, &resourcePath);
   if (error)
   {
      LOG_ERROR_MESSAGE("Unable to determine install path: "+error.summary());
      return ProgramStatus::exitFailure();
   }

   // detect running in OSX bundle and tweak resource path
#ifdef __APPLE__
   if (resourcePath.complete("Info.plist").exists())
      resourcePath = resourcePath.complete("Resources");
#endif

   // detect running in x64 directory and tweak resource path
#ifdef _WIN32
   if (resourcePath.complete("x64").exists())
      resourcePath = resourcePath.parent();
#endif

   // program - name and execution
   options_description program("program");
   program.add_options()
      (kProgramModeSessionOption,
         value<std::string>(&programMode_)->default_value("server"),
         "program mode (desktop or server");
   
   // agreement
   options_description agreement("agreement");
   agreement.add_options()
      ("agreement-file",
      value<std::string>(&agreementFilePath_)->default_value(""),
      "agreement file");

   // docs url
   options_description docs("docs");
   docs.add_options()
      ("docs-url",
       value<std::string>(&docsURL_)->default_value(""),
       "custom docs url");

   // www options
   options_description www("www") ;
   www.add_options()
      ("www-local-path",
         value<std::string>(&wwwLocalPath_)->default_value("www"),
         "www local path")
      ("www-port",
         value<std::string>(&wwwPort_)->default_value("8787"),
         "port to listen on");

   // session options
   options_description session("session") ;
   session.add_options()
      ("session-timeout-minutes",
         value<int>(&timeoutMinutes_)->default_value(120),
         "session timeout (minutes)" )
      ("session-preflight-script",
         value<std::string>(&preflightScript_)->default_value(""),
         "session preflight script")
      ("session-create-public-folder",
         value<bool>(&createPublicFolder_)->default_value(false),
         "automatically create public folder");

   // r options
   options_description r("r") ;
   r.add_options()
      ("r-core-source",
         value<std::string>(&coreRSourcePath_)->default_value("R"),
         "Core R source path")
      ("r-modules-source", 
         value<std::string>(&modulesRSourcePath_)->default_value("R/modules"),
         "Modules R source path")
      ("r-session-packages",
         value<std::string>(&sessionPackagesPath_)->default_value("R/library"),
         "R packages path")
      ("r-libs-user",
         value<std::string>(&rLibsUser_)->default_value("~/R/library"),
         "R user library path")
      ("r-cran-repos",
         value<std::string>(&rCRANRepos_)->default_value(""),
         "Default CRAN repository")
      ("r-auto-reload-source",
         value<bool>(&autoReloadSource_)->default_value(false),
         "Reload R source if it changes during the session")
      ("r-compatible-graphics-engine-version",
         value<int>(&rCompatibleGraphicsEngineVersion_)->default_value(8),
         "Maximum graphics engine version we are compatible with")
      ("r-css-file",
         value<std::string>(&rHelpCssFilePath_)->default_value("resources/R.css"),
         "Custom R.css file")
      ("r-shell-escape",
         value<bool>(&rShellEscape_)->default_value(false),
         "Support shell escape");

   // limits options
   options_description limits("limits");
   limits.add_options()
      ("limit-file-upload-size-mb",
       value<int>(&limitFileUploadSizeMb_)->default_value(0),
       "limit of file upload size")
      ("limit-cpu-time-minutes",
       value<int>(&limitCpuTimeMinutes_)->default_value(0),
       "limit on time of top level computations")
      ("limit-xfs-disk-quota",
       value<bool>(&limitXfsDiskQuota_)->default_value(false),
       "limit xfs disk quota");
   
   // external options
   options_description external("external");
   external.add_options()
      ("external-rpostback-path", 
       value<std::string>(&rpostbackPath_)->default_value("bin/rpostback"),
       "Path to rpostback executable");
   
   // user options (default user identity to current username)
   std::string currentUsername = core::system::username();
   options_description user("user") ;
   user.add_options()
      (kUserIdentitySessionOption "," kUserIdentitySessionOptionShort,
       value<std::string>(&userIdentity_)->default_value(currentUsername),
       "user identity" );
   
   // define program options
   FilePath defaultConfigPath("/etc/rstudio/rsession.conf");
   std::string configFile = defaultConfigPath.exists() ?
                                 defaultConfigPath.absolutePath() : "";
   core::program_options::OptionsDescription optionsDesc("rsession",
                                                         configFile);

   optionsDesc.commandLine.add(program);
   optionsDesc.commandLine.add(agreement);
   optionsDesc.commandLine.add(docs);
   optionsDesc.commandLine.add(www);
   optionsDesc.commandLine.add(session);
   optionsDesc.commandLine.add(r);
   optionsDesc.commandLine.add(limits);
   optionsDesc.commandLine.add(external);
   optionsDesc.commandLine.add(user);
   
   // define groups included in config-file processing
   optionsDesc.configFile.add(program);
   optionsDesc.configFile.add(agreement);
   optionsDesc.configFile.add(docs);
   optionsDesc.configFile.add(www);
   optionsDesc.configFile.add(session);
   optionsDesc.configFile.add(r);
   optionsDesc.configFile.add(limits);
   optionsDesc.configFile.add(external);
   optionsDesc.configFile.add(user);

   // read configuration
   ProgramStatus status = core::program_options::read(optionsDesc, argc,argv);
   if (status.exit())
      return status;
   
   // make sure the program mode is valid
   if (programMode_ != kSessionProgramModeDesktop &&
       programMode_ != kSessionProgramModeServer)
   {
      LOG_ERROR_MESSAGE("invalid program mode: " + programMode_);
      return ProgramStatus::exitFailure();
   }

   // compute program identity
   programIdentity_ = "rsession-" + userIdentity_;

   // compute user home path
   FilePath userHomePath = core::system::userHomePath("R_USER|HOME");
   userHomePath_ = userHomePath.absolutePath();

   // compute user scratch path
   std::string scratchPathName;
   if (programMode_ == kSessionProgramModeDesktop)
      scratchPathName = "RStudio-Desktop";
   else
      scratchPathName = "RStudio";
   userScratchPath_ = core::system::userSettingsPath(
                                       userHomePath,
                                       scratchPathName).absolutePath();

   // session timeout seconds is always -1 in desktop mode
   if (programMode_ == kSessionProgramModeDesktop)
      timeoutMinutes_ = 0;

   // if we are in desktop mode and no agreement file path was
   // specified then default to gpl-standalone
   if ( (programMode_ == kSessionProgramModeDesktop) &&
        agreementFilePath_.empty())
   {
      agreementFilePath_ = "resources/agpl-3.0-standalone.html";
   }

   // convert relative paths by completing from the app resource path
   resolvePath(resourcePath, &rHelpCssFilePath_);
   resolvePath(resourcePath, &agreementFilePath_);
   resolvePath(resourcePath, &wwwLocalPath_);
   resolvePath(resourcePath, &coreRSourcePath_);
   resolvePath(resourcePath, &modulesRSourcePath_);
   resolvePath(resourcePath, &sessionPackagesPath_);
   resolvePath(resourcePath, &rpostbackPath_);

   // shared secret with parent
   secret_ = core::system::getenv("RS_SHARED_SECRET");
   core::system::unsetenv("RS_SHARED_SECRET");

   // initial working dir override
   initialWorkingDirOverride_ = core::system::getenv("RS_INITIAL_WD");
   core::system::unsetenv("RS_INITIAL_WD");

   // initial environment file override
   initialEnvironmentFileOverride_ = core::system::getenv("RS_INITIAL_ENV");
   core::system::unsetenv("RS_INITIAL_ENV");

   // limit rpc client uid
   limitRpcClientUid_ = -1;
   std::string limitUid = core::system::getenv(kRStudioLimitRpcClientUid);
   if (!limitUid.empty())
   {
      limitRpcClientUid_ = core::safe_convert::stringTo<int>(limitUid, -1);
      core::system::unsetenv(kRStudioLimitRpcClientUid);
   }

   // return status
   return status;
}
Beispiel #21
0
Error saveDocumentCore(const std::string& contents,
                       const json::Value& jsonPath,
                       const json::Value& jsonType,
                       const json::Value& jsonEncoding,
                       const json::Value& jsonFoldSpec,
                       boost::shared_ptr<SourceDocument> pDoc)
{
   // check whether we have a path and if we do get/resolve its value
   std::string path;
   FilePath fullDocPath;
   bool hasPath = json::isType<std::string>(jsonPath);
   if (hasPath)
   {
      path = jsonPath.get_str();
      fullDocPath = module_context::resolveAliasedPath(path);
   }
   
   // update dirty state: dirty if there was no path AND the new contents
   // are different from the old contents (and was thus a content autosave
   // as distinct from a fold-spec or scroll-position/selection autosave)
   pDoc->setDirty(!hasPath && (contents != pDoc->contents()));
   
   bool hasType = json::isType<std::string>(jsonType);
   if (hasType)
   {
      pDoc->setType(jsonType.get_str());
   }
   
   Error error;
   
   bool hasEncoding = json::isType<std::string>(jsonEncoding);
   if (hasEncoding)
   {
      pDoc->setEncoding(jsonEncoding.get_str());
   }

   bool hasFoldSpec = json::isType<std::string>(jsonFoldSpec);
   if (hasFoldSpec)
   {
      pDoc->setFolds(jsonFoldSpec.get_str());
   }

   // handle document (varies depending upon whether we have a path)
   if (hasPath)
   {
      std::string encoded;
      error = r::util::iconvstr(contents,
                                "UTF-8",
                                pDoc->encoding(),
                                false,
                                &encoded);
      if (error)
      {
         error = r::util::iconvstr(contents,
                                   "UTF-8",
                                   pDoc->encoding(),
                                   true,
                                   &encoded);
         if (error)
            return error;


         module_context::consoleWriteError(
                          "Not all of the characters in " + path +
                          " could be encoded using " + pDoc->encoding() +
                          ". To save using a different encoding, choose \"File | "
                          "Save with Encoding...\" from the main menu.");
      }

      // note whether the file existed prior to writing
      bool newFile = !fullDocPath.exists();

      // write the contents to the file
      error = writeStringToFile(fullDocPath, encoded,
                                options().sourcePersistLineEnding());
      if (error)
         return error ;

      // set the new path and contents for the document
      error = pDoc->setPathAndContents(path);
      if (error)
         return error ;

      // enque file changed event if we need to
      if (!module_context::isDirectoryMonitored(fullDocPath.parent()))
      {
         using core::system::FileChangeEvent;
         FileChangeEvent changeEvent(newFile ? FileChangeEvent::FileAdded :
                                               FileChangeEvent::FileModified,
                                     FileInfo(fullDocPath));
         module_context::enqueFileChangedEvent(changeEvent);
      }

      // notify other server modules of the file save
      module_context::events().onSourceEditorFileSaved(fullDocPath);

      // save could change the extended type of the file so check it
      detectExtendedType(pDoc);
   }

   // always update the contents so it holds the original UTF-8 data
   pDoc->setContents(contents);

   return Success();
}
Beispiel #22
0
 void init(const FilePath& targetFilePath)
 {
    basePath_ = targetFilePath.parent().childPath(
                                  targetFilePath.stem()).absolutePath();
 }
Beispiel #23
0
FilePath ancillaryFilePath(const FilePath& texFilePath, const std::string& ext)
{
   return texFilePath.parent().childPath(texFilePath.stem() + ext);
}
core::ProgramStatus Options::read(int argc, char * const argv[])
{
   using namespace boost::program_options ;
   
   // get the shared secret
   monitorSharedSecret_ = core::system::getenv(kMonitorSharedSecretEnvVar);
   core::system::unsetenv(kMonitorSharedSecretEnvVar);

   // compute the resource path
   FilePath resourcePath;
   Error error = core::system::installPath("..", argv[0], &resourcePath);
   if (error)
   {
      LOG_ERROR_MESSAGE("Unable to determine install path: "+error.summary());
      return ProgramStatus::exitFailure();
   }

   // detect running in OSX bundle and tweak resource path
#ifdef __APPLE__
   if (resourcePath.complete("Info.plist").exists())
      resourcePath = resourcePath.complete("Resources");
#endif

   // detect running in x64 directory and tweak resource path
#ifdef _WIN32
   if (resourcePath.complete("x64").exists())
      resourcePath = resourcePath.parent();
#endif

   // verify installation flag
   options_description verify("verify");
   verify.add_options()
     (kVerifyInstallationSessionOption,
     value<bool>(&verifyInstallation_)->default_value(false),
     "verify the current installation");

   // program - name and execution
   options_description program("program");
   program.add_options()
      (kProgramModeSessionOption,
         value<std::string>(&programMode_)->default_value("server"),
         "program mode (desktop or server");
   
   // log -- logging options
   options_description log("log");
   log.add_options()
      ("log-stderr",
      value<bool>(&logStderr_)->default_value(true),
      "write log entries to stderr");

   // agreement
   options_description agreement("agreement");
   agreement.add_options()
      ("agreement-file",
      value<std::string>(&agreementFilePath_)->default_value(""),
      "agreement file");

   // docs url
   options_description docs("docs");
   docs.add_options()
      ("docs-url",
       value<std::string>(&docsURL_)->default_value(""),
       "custom docs url");

   // www options
   options_description www("www") ;
   www.add_options()
      ("www-local-path",
         value<std::string>(&wwwLocalPath_)->default_value("www"),
         "www local path")
      ("www-symbol-maps-path",
         value<std::string>(&wwwSymbolMapsPath_)->default_value(
                                                         "www-symbolmaps"),
         "www symbol maps path")
      ("www-port",
         value<std::string>(&wwwPort_)->default_value("8787"),
         "port to listen on")
      ("www-address",
         value<std::string>(&wwwAddress_)->default_value("127.0.0.1"),
         "port to listen on")
      ("standalone",
         value<bool>(&standalone_)->default_value(false),
         "run standalone");

   // session options
   std::string saveActionDefault;
   options_description session("session") ;
   session.add_options()
      (kTimeoutSessionOption,
         value<int>(&timeoutMinutes_)->default_value(120),
         "session timeout (minutes)" )
      (kDisconnectedTimeoutSessionOption,
         value<int>(&disconnectedTimeoutMinutes_)->default_value(0),
         "session disconnected timeout (minutes)" )
      ("session-preflight-script",
         value<std::string>(&preflightScript_)->default_value(""),
         "session preflight script")
      ("session-create-public-folder",
         value<bool>(&createPublicFolder_)->default_value(false),
         "automatically create public folder")
      ("session-create-profile",
         value<bool>(&createProfile_)->default_value(false),
         "automatically create .Rprofile")
      ("session-rprofile-on-resume-default",
          value<bool>(&rProfileOnResumeDefault_)->default_value(false),
          "default user setting for running Rprofile on resume")
      ("session-save-action-default",
       value<std::string>(&saveActionDefault)->default_value(""),
          "default save action (yes, no, or ask)");

   // allow options
   options_description allow("allow");
   allow.add_options()
      ("allow-vcs-executable-edit",
         value<bool>(&allowVcsExecutableEdit_)->default_value(true),
         "allow editing of vcs executables")
      ("allow-r-cran-repos-edit",
         value<bool>(&allowCRANReposEdit_)->default_value(true),
         "Allow editing of CRAN repository")
      ("allow-vcs",
         value<bool>(&allowVcs_)->default_value(true),
         "allow use of version control features")
      ("allow-package-installation",
         value<bool>(&allowPackageInstallation_)->default_value(true),
         "allow installation of packages from the packages pane")
      ("allow-shell",
         value<bool>(&allowShell_)->default_value(true),
         "allow access to shell dialog")
      ("allow-file-downloads",
         value<bool>(&allowFileDownloads_)->default_value(true),
         "allow file downloads from the files pane")
      ("allow-remove-public-folder",
         value<bool>(&allowRemovePublicFolder_)->default_value(true),
         "allow removal of the user public folder")
      ("allow-rpubs-publish",
         value<bool>(&allowRpubsPublish_)->default_value(true),
        "allow publishing to rpubs");

   // r options
   bool rShellEscape; // no longer works but don't want to break any
                      // config files which formerly used it
                      // TODO: eliminate this option entirely
   options_description r("r") ;
   r.add_options()
      ("r-core-source",
         value<std::string>(&coreRSourcePath_)->default_value("R"),
         "Core R source path")
      ("r-modules-source", 
         value<std::string>(&modulesRSourcePath_)->default_value("R/modules"),
         "Modules R source path")
      ("r-session-library",
         value<std::string>(&sessionLibraryPath_)->default_value("R/library"),
         "R library path")
      ("r-session-packages",
         value<std::string>(&sessionPackagesPath_)->default_value("R/packages"),
         "R packages path")
      ("r-session-package-archives",
          value<std::string>(&sessionPackageArchivesPath_)->default_value("R/packages"),
         "R package archives path")
      ("r-libs-user",
         value<std::string>(&rLibsUser_)->default_value(""),
         "R user library path")
      ("r-cran-repos",
         value<std::string>(&rCRANRepos_)->default_value(""),
         "Default CRAN repository")
      ("r-auto-reload-source",
         value<bool>(&autoReloadSource_)->default_value(false),
         "Reload R source if it changes during the session")
      ("r-compatible-graphics-engine-version",
         value<int>(&rCompatibleGraphicsEngineVersion_)->default_value(10),
         "Maximum graphics engine version we are compatible with")
      ("r-resources-path",
         value<std::string>(&rResourcesPath_)->default_value("resources"),
         "Directory containing external resources")
      ("r-shell-escape",
         value<bool>(&rShellEscape)->default_value(false),
         "Support shell escape (deprecated, no longer works)")
      ("r-home-dir-override",
         value<std::string>(&rHomeDirOverride_)->default_value(""),
         "Override for R_HOME (used for debug configurations)")
      ("r-doc-dir-override",
         value<std::string>(&rDocDirOverride_)->default_value(""),
         "Override for R_DOC_DIR (used for debug configurations)");

   // limits options
   options_description limits("limits");
   limits.add_options()
      ("limit-file-upload-size-mb",
       value<int>(&limitFileUploadSizeMb_)->default_value(0),
       "limit of file upload size")
      ("limit-cpu-time-minutes",
       value<int>(&limitCpuTimeMinutes_)->default_value(0),
       "limit on time of top level computations")
      ("limit-xfs-disk-quota",
       value<bool>(&limitXfsDiskQuota_)->default_value(false),
       "limit xfs disk quota");
   
   // external options
   options_description external("external");
   external.add_options()
      ("external-rpostback-path", 
       value<std::string>(&rpostbackPath_)->default_value(kDefaultPostbackPath),
       "Path to rpostback executable")
      ("external-consoleio-path",
       value<std::string>(&consoleIoPath_)->default_value("bin/consoleio.exe"),
       "Path to consoleio executable")
      ("external-gnudiff-path",
       value<std::string>(&gnudiffPath_)->default_value("bin/gnudiff"),
       "Path to gnudiff utilities (windows-only)")
      ("external-gnugrep-path",
       value<std::string>(&gnugrepPath_)->default_value("bin/gnugrep"),
       "Path to gnugrep utilities (windows-only)")
      ("external-msysssh-path",
       value<std::string>(&msysSshPath_)->default_value("bin/msys_ssh"),
       "Path to msys_ssh utilities (windows-only)")
      ("external-sumatra-path",
       value<std::string>(&sumatraPath_)->default_value("bin/sumatra"),
       "Path to SumatraPDF (windows-only)")
      ("external-hunspell-dictionaries-path",
       value<std::string>(&hunspellDictionariesPath_)->default_value("resources/dictionaries"),
       "Path to hunspell dictionaries")
      ("external-mathjax-path",
        value<std::string>(&mathjaxPath_)->default_value("resources/mathjax-23"),
        "Path to mathjax library")
      ("external-pandoc-path",
        value<std::string>(&pandocPath_)->default_value(kDefaultPandocPath),
        "Path to pandoc binaries");

   // user options (default user identity to current username)
   std::string currentUsername = core::system::username();
   options_description user("user") ;
   user.add_options()
      (kUserIdentitySessionOption "," kUserIdentitySessionOptionShort,
       value<std::string>(&userIdentity_)->default_value(currentUsername),
       "user identity" )
      (kShowUserIdentitySessionOption,
       value<bool>(&showUserIdentity_)->default_value(true),
       "show the user identity");

   // overlay options
   options_description overlay("overlay");
   addOverlayOptions(&overlay);

   // define program options
   FilePath defaultConfigPath("/etc/rstudio/rsession.conf");
   std::string configFile = defaultConfigPath.exists() ?
                                 defaultConfigPath.absolutePath() : "";
   core::program_options::OptionsDescription optionsDesc("rsession",
                                                         configFile);

   optionsDesc.commandLine.add(verify);
   optionsDesc.commandLine.add(program);
   optionsDesc.commandLine.add(log);
   optionsDesc.commandLine.add(agreement);
   optionsDesc.commandLine.add(docs);
   optionsDesc.commandLine.add(www);
   optionsDesc.commandLine.add(session);
   optionsDesc.commandLine.add(allow);
   optionsDesc.commandLine.add(r);
   optionsDesc.commandLine.add(limits);
   optionsDesc.commandLine.add(external);
   optionsDesc.commandLine.add(user);

   // define groups included in config-file processing
   optionsDesc.configFile.add(program);
   optionsDesc.configFile.add(log);
   optionsDesc.configFile.add(agreement);
   optionsDesc.configFile.add(docs);
   optionsDesc.configFile.add(www);
   optionsDesc.configFile.add(session);
   optionsDesc.configFile.add(allow);
   optionsDesc.configFile.add(r);
   optionsDesc.configFile.add(limits);
   optionsDesc.configFile.add(external);
   optionsDesc.configFile.add(user);
   optionsDesc.configFile.add(overlay);

   // read configuration
   ProgramStatus status = core::program_options::read(optionsDesc, argc,argv);
   if (status.exit())
      return status;
   
   // make sure the program mode is valid
   if (programMode_ != kSessionProgramModeDesktop &&
       programMode_ != kSessionProgramModeServer)
   {
      LOG_ERROR_MESSAGE("invalid program mode: " + programMode_);
      return ProgramStatus::exitFailure();
   }

   // call overlay hooks
   resolveOverlayOptions();
   std::string errMsg;
   if (!validateOverlayOptions(&errMsg))
   {
      program_options::reportError(errMsg, ERROR_LOCATION);
      return ProgramStatus::exitFailure();
   }

   // compute program identity
   programIdentity_ = "rsession-" + userIdentity_;

   // provide special home path in temp directory if we are verifying
   if (verifyInstallation_)
   {
      // we create a special home directory in server mode (since the
      // user we are running under might not have a home directory)
      if (programMode_ == kSessionProgramModeServer)
      {
         verifyInstallationHomeDir_ = "/tmp/rstudio-verify-installation";
         Error error = FilePath(verifyInstallationHomeDir_).ensureDirectory();
         if (error)
         {
            LOG_ERROR(error);
            return ProgramStatus::exitFailure();
         }
         core::system::setenv("R_USER", verifyInstallationHomeDir_);
      }
   }

   // compute user paths
   r_util::SessionType sessionType =
      (programMode_ == kSessionProgramModeDesktop) ?
                                    r_util::SessionTypeDesktop :
                                    r_util::SessionTypeServer;

   r_util::UserDirectories userDirs = r_util::userDirectories(sessionType);
   userHomePath_ = userDirs.homePath;
   userScratchPath_ = userDirs.scratchPath;

   // set HOME if we are in standalone mode (this enables us to reflect
   // R_USER back into HOME on Linux)
   if (standalone())
      core::system::setenv("HOME", userHomePath_);

   // session timeout seconds is always -1 in desktop mode
   if (programMode_ == kSessionProgramModeDesktop)
      timeoutMinutes_ = 0;

   // convert string save action default to intenger
   if (saveActionDefault == "yes")
      saveActionDefault_ = r::session::kSaveActionSave;
   else if (saveActionDefault == "no")
      saveActionDefault_ = r::session::kSaveActionNoSave;
   else if (saveActionDefault == "ask" || saveActionDefault.empty())
      saveActionDefault_ = r::session::kSaveActionAsk;
   else
   {
      program_options::reportWarnings(
         "Invalid value '" + saveActionDefault + "' for "
         "session-save-action-default. Valid values are yes, no, and ask.",
         ERROR_LOCATION);
      saveActionDefault_ = r::session::kSaveActionAsk;
   }

   // convert relative paths by completing from the app resource path
   resolvePath(resourcePath, &rResourcesPath_);
   resolvePath(resourcePath, &agreementFilePath_);
   resolvePath(resourcePath, &wwwLocalPath_);
   resolvePath(resourcePath, &wwwSymbolMapsPath_);
   resolvePath(resourcePath, &coreRSourcePath_);
   resolvePath(resourcePath, &modulesRSourcePath_);
   resolvePath(resourcePath, &sessionLibraryPath_);
   resolvePath(resourcePath, &sessionPackagesPath_);
   resolvePath(resourcePath, &sessionPackageArchivesPath_);
   resolvePostbackPath(resourcePath, &rpostbackPath_);
#ifdef _WIN32
   resolvePath(resourcePath, &consoleIoPath_);
   resolvePath(resourcePath, &gnudiffPath_);
   resolvePath(resourcePath, &gnugrepPath_);
   resolvePath(resourcePath, &msysSshPath_);
   resolvePath(resourcePath, &sumatraPath_);
#endif
   resolvePath(resourcePath, &hunspellDictionariesPath_);
   resolvePath(resourcePath, &mathjaxPath_);
   resolvePandocPath(resourcePath, &pandocPath_);

   // shared secret with parent
   secret_ = core::system::getenv("RS_SHARED_SECRET");
   /* SECURITY: Need RS_SHARED_SECRET to be available to
      rpostback. However, we really ought to communicate
      it in a more secure manner than this, at least on
      Windows where even within the same user session some
      processes can have different priviliges (integrity
      levels) than others. For example, using a named pipe
      with proper SACL to retrieve the shared secret, where
      the name of the pipe is in an environment variable. */
   //core::system::unsetenv("RS_SHARED_SECRET");

   // initial working dir override
   initialWorkingDirOverride_ = core::system::getenv(kRStudioInitialWorkingDir);
   core::system::unsetenv(kRStudioInitialWorkingDir);

   // initial environment file override
   initialEnvironmentFileOverride_ = core::system::getenv(kRStudioInitialEnvironment);
   core::system::unsetenv(kRStudioInitialEnvironment);

   // initial project
   initialProjectPath_ = core::system::getenv(kRStudioInitialProject);
   core::system::unsetenv(kRStudioInitialProject);

   // limit rpc client uid
   limitRpcClientUid_ = -1;
   std::string limitUid = core::system::getenv(kRStudioLimitRpcClientUid);
   if (!limitUid.empty())
   {
      limitRpcClientUid_ = core::safe_convert::stringTo<int>(limitUid, -1);
      core::system::unsetenv(kRStudioLimitRpcClientUid);
   }

   // return status
   return status;
}
Beispiel #25
0
// NOTE: this function is called very early in the process lifetime (from
// session::projects::startup) so can only have limited dependencies.
// specifically, it can rely on userSettings() being available, but can
// definitely NOT rely on calling into R. For initialization related tasks
// that need to run after R is available use the implementation of the
// initialize method (below)
Error ProjectContext::startup(const FilePath& projectFile,
                              std::string* pUserErrMsg)
{
   // test for project file existence
   if (!projectFile.exists())
   {
      *pUserErrMsg = "the project file does not exist";
      return pathNotFoundError(projectFile.absolutePath(), ERROR_LOCATION);
   }

   // test for writeabilty of parent
   if (!canWriteToProjectDir(projectFile.parent()))
   {
      *pUserErrMsg = "the project directory is not writeable";
      return systemError(boost::system::errc::permission_denied,
                         ERROR_LOCATION);
   }

   // calculate project scratch path
   FilePath scratchPath;
   FilePath sharedScratchPath;
   Error error = computeScratchPaths(projectFile, &scratchPath,
         &sharedScratchPath);
   if (error)
   {
      *pUserErrMsg = "unable to initialize project - " + error.summary();
      return error;
   }

   // read project file config
   bool providedDefaults;
   r_util::RProjectConfig config;
   error = r_util::readProjectFile(projectFile,
                                   defaultConfig(),
                                   buildDefaults(),
                                   &config,
                                   &providedDefaults,
                                   pUserErrMsg);
   if (error)
      return error;

   // update package install args with new defaults (one time only)
   ProjectsSettings projSettings(options().userScratchPath());
   const char * kUpdatePackageInstallDefault = "update-pkg-install-default";
   if (projSettings.readSetting(kUpdatePackageInstallDefault).empty())
   {
      projSettings.writeSetting(kUpdatePackageInstallDefault, "1");
      if (r_util::updateSetPackageInstallArgsDefault(&config))
         providedDefaults = true;
   }

   // if we provided defaults then re-write the project file
   // with the defaults
   if (providedDefaults)
   {
      error = r_util::writeProjectFile(projectFile, buildDefaults(), config);
      if (error)
         LOG_ERROR(error);
   }

   // initialize members
   file_ = projectFile;
   directory_ = file_.parent();
   scratchPath_ = scratchPath;
   sharedScratchPath_ = sharedScratchPath;
   config_ = config;

   // assume true so that the initial files pane listing doesn't register
   // a duplicate monitor. if it turns out to be false then this can be
   // repaired by a single refresh of the files pane
   hasFileMonitor_ = config_.enableCodeIndexing;

   // return success
   return Success();

}
Beispiel #26
0
Error parseLatexLog(const FilePath& logFilePath, LogEntries* pLogEntries)
{
   static boost::regex regexOverUnderfullLines(" at lines (\\d+)--(\\d+)\\s*(?:\\[])?$");
   static boost::regex regexWarning("^(?:.*?) Warning: (.+)");
   static boost::regex regexWarningEnd(" input line (\\d+)\\.$");
   static boost::regex regexLnn("^l\\.(\\d+)\\s");
   static boost::regex regexCStyleError("^(.+):(\\d+):\\s(.+)$");

   std::vector<std::string> lines;
   Error error = readStringVectorFromFile(logFilePath, &lines, false);
   if (error)
      return error;

   std::vector<size_t> linesUnwrapped;
   unwrapLines(&lines, &linesUnwrapped);

   FilePath rootDir = logFilePath.parent();
   FileStack fileStack(rootDir);

   for (std::vector<std::string>::const_iterator it = lines.begin();
        it != lines.end();
        it++)
   {
      const std::string& line = *it;
      int logLineNum = (it - lines.begin()) + 1;

      // We slurp overfull/underfull messages with no further processing
      // (i.e. not manipulating the file stack)

      if (beginsWith(line, "Overfull ", "Underfull "))
      {
         std::string msg = line;
         int lineNum = -1;

         // Parse lines, if present
         boost::smatch overUnderfullLinesMatch;
         if (boost::regex_search(line,
                                 overUnderfullLinesMatch,
                                 regexOverUnderfullLines))
         {
            lineNum = safe_convert::stringTo<int>(overUnderfullLinesMatch[1],
                                                  -1);
         }

         // Single line case
         bool singleLine = boost::algorithm::ends_with(line, "[]");

         if (singleLine)
         {
            msg.erase(line.size()-2, 2);
            boost::algorithm::trim_right(msg);
         }

         pLogEntries->push_back(LogEntry(logFilePath,
                                         calculateWrappedLine(linesUnwrapped,
                                                              logLineNum),
                                         LogEntry::Box,
                                         fileStack.currentFile(),
                                         lineNum,
                                         msg));

         if (singleLine)
            continue;

         for (; it != lines.end(); it++)
         {
            // For multi-line case, we're looking for " []" on a line by itself
            if (*it == " []")
               break;
         }

         // The iterator would be incremented by the outer for loop, must not
         // let it go past the end! (If we did get to the end, it would
         // mean the log file was malformed, but we still can't crash in this
         // situation.)
         if (it == lines.end())
            break;
         else
            continue;
      }

      fileStack.processLine(line);

      // Now see if it's an error or warning

      if (beginsWith(line, "! "))
      {
         std::string errorMsg = line.substr(2);
         int lineNum = -1;

         boost::smatch match;
         for (it++; it != lines.end(); it++)
         {
            if (boost::regex_search(*it, match, regexLnn))
            {
               lineNum = safe_convert::stringTo<int>(match[1], -1);
               break;
            }
         }

         pLogEntries->push_back(LogEntry(logFilePath,
                                         calculateWrappedLine(linesUnwrapped,
                                                              logLineNum),
                                         LogEntry::Error,
                                         fileStack.currentFile(),
                                         lineNum,
                                         errorMsg));

         // The iterator would be incremented by the outer for loop, must not
         // let it go past the end! (If we did get to the end, it would
         // mean the log file was malformed, but we still can't crash in this
         // situation.)
         if (it == lines.end())
            break;
         else
            continue;
      }

      boost::smatch warningMatch;
      if (boost::regex_search(line, warningMatch, regexWarning))
      {
         std::string warningMsg = warningMatch[1];
         int lineNum = -1;
         while (true)
         {
            if (boost::algorithm::ends_with(warningMsg, "."))
            {
               boost::smatch warningEndMatch;
               if (boost::regex_search(*it, warningEndMatch, regexWarningEnd))
               {
                  lineNum = safe_convert::stringTo<int>(warningEndMatch[1], -1);
               }
               break;
            }

            if (++it == lines.end())
               break;
            warningMsg.append(*it);
         }

         pLogEntries->push_back(LogEntry(logFilePath,
                                         calculateWrappedLine(linesUnwrapped,
                                                              logLineNum),
                                         LogEntry::Warning,
                                         fileStack.currentFile(),
                                         lineNum,
                                         warningMsg));

         // The iterator would be incremented by the outer for loop, must not
         // let it go past the end! (If we did get to the end, it would
         // mean the log file was malformed, but we still can't crash in this
         // situation.)
         if (it == lines.end())
            break;
         else
            continue;
      }

      boost::smatch cStyleErrorMatch;
      if (boost::regex_search(line, cStyleErrorMatch, regexCStyleError))
      {
         FilePath cstyleFile = resolveFilename(rootDir, cStyleErrorMatch[1]);
         if (cstyleFile.exists())
         {
            int lineNum = safe_convert::stringTo<int>(cStyleErrorMatch[2], -1);
            pLogEntries->push_back(LogEntry(logFilePath,
                                            calculateWrappedLine(linesUnwrapped,
                                                                 logLineNum),
                                            LogEntry::Error,
                                            cstyleFile,
                                            lineNum,
                                            cStyleErrorMatch[3]));
         }
      }
   }

   return Success();
}
Beispiel #27
0
Error createProject(const json::JsonRpcRequest& request,
                    json::JsonRpcResponse* pResponse)
{
   // read params
   std::string projectFile;
   json::Value newPackageJson;
   json::Value newShinyAppJson;
   Error error = json::readParams(request.params,
                                  &projectFile,
                                  &newPackageJson,
                                  &newShinyAppJson);
   if (error)
      return error;
   FilePath projectFilePath = module_context::resolveAliasedPath(projectFile);

   if (!newShinyAppJson.is_null())
   {
      // error if the shiny app dir already exists
      FilePath appDir = projectFilePath.parent();
      if (appDir.exists())
         return core::fileExistsError(ERROR_LOCATION);

      // now create it
      Error error = appDir.ensureDirectory();
      if (error)
         return error;

      // copy ui.R and server.R into the project
      const char * const kUI = "ui.R";
      const char * const kServer = "server.R";
      std::string shinyVer;
      if (module_context::isPackageVersionInstalled("shiny", "0.9"))
         shinyVer = "shiny-0.9";
      else
         shinyVer = "shiny";
      FilePath shinyDir = session::options().rResourcesPath().childPath(
                                                     "templates/" + shinyVer);
      error = shinyDir.childPath(kUI).copy(appDir.childPath(kUI));
      if (error)
         LOG_ERROR(error);
      error = shinyDir.childPath(kServer).copy(appDir.childPath(kServer));
      if (error)
         LOG_ERROR(error);

      // add first run actions for the source files
      addFirstRunDoc(projectFilePath, kUI);
      addFirstRunDoc(projectFilePath, kServer);

      // create the project file
      return r_util::writeProjectFile(projectFilePath,
                                      ProjectContext::buildDefaults(),
                                      ProjectContext::defaultConfig());
   }

   // default project
   else
   {
      // create the project directory if necessary
      error = projectFilePath.parent().ensureDirectory();
      if (error)
         return error;

      // create the project file
      if (!projectFilePath.exists())
      {
         return r_util::writeProjectFile(projectFilePath,
                                         ProjectContext::buildDefaults(),
                                         ProjectContext::defaultConfig());
      }
      else
      {
         return Success();
      }
   }
}
Beispiel #28
0
Error createProject(const json::JsonRpcRequest& request,
                    json::JsonRpcResponse* pResponse)
{
   // read params
   std::string projectFile;
   json::Value newPackageJson;
   Error error = json::readParams(request.params,
                                  &projectFile,
                                  &newPackageJson);
   if (error)
      return error;
   FilePath projectFilePath = module_context::resolveAliasedPath(projectFile);

   // default project
   if (newPackageJson.is_null())
   {
      // create the project directory if necessary
      error = projectFilePath.parent().ensureDirectory();
      if (error)
         return error;

      // create the project file
      if (!projectFilePath.exists())
      {
         return r_util::writeProjectFile(projectFilePath,
                                         ProjectContext::defaultConfig());
      }
      else
      {
         return Success();
      }
   }

   // package project
   else
   {
      // build list of code files
      bool usingRcpp;
      json::Array codeFilesJson;
      Error error = json::readObject(newPackageJson.get_obj(),
                                     "using_rcpp", &usingRcpp,
                                     "code_files", &codeFilesJson);
      if (error)
         return error;
      std::vector<FilePath> codeFiles;
      BOOST_FOREACH(const json::Value codeFile, codeFilesJson)
      {
         if (!json::isType<std::string>(codeFile))
         {
            BOOST_ASSERT(false);
            continue;
         }

         FilePath codeFilePath =
                     module_context::resolveAliasedPath(codeFile.get_str());
         codeFiles.push_back(codeFilePath);
      }

      // error if the package dir already exists
      FilePath packageDir = projectFilePath.parent();
      if (packageDir.exists())
         return core::fileExistsError(ERROR_LOCATION);

      // create a temp dir (so we can import the list of code files)
      FilePath tempDir = module_context::tempFile("newpkg", "dir");
      error = tempDir.ensureDirectory();
      if (error)
         return error;

      // copy the code files into the tempDir and build up a
      // list of the filenames for passing to package.skeleton
      std::vector<std::string> rFileNames, cppFileNames;
      BOOST_FOREACH(const FilePath& codeFilePath, codeFiles)
      {
         FilePath targetPath = tempDir.complete(codeFilePath.filename());
         Error error = codeFilePath.copy(targetPath);
         if (error)
            return error;

         std::string ext = targetPath.extensionLowerCase();
         std::string file = string_utils::utf8ToSystem(targetPath.filename());
         if (boost::algorithm::starts_with(ext,".c"))
            cppFileNames.push_back(file);
         else
            rFileNames.push_back(file);
      }


      // if the list of code files is empty then add an empty file
      // with the same name as the package (but don't do this for
      // Rcpp since it generates a hello world file)
      if (codeFiles.empty() && !usingRcpp)
      {
         std::string srcFileName = packageDir.filename() + ".R";
         FilePath srcFilePath = tempDir.complete(srcFileName);
         Error error = core::writeStringToFile(srcFilePath, "");
         if (error)
            return error;
         rFileNames.push_back(string_utils::utf8ToSystem(srcFileName));
      }

      // temporarily switch to the tempDir for package creation
      RestoreCurrentPathScope pathScope(module_context::safeCurrentPath());
      tempDir.makeCurrentPath();

      // call package.skeleton

      r::exec::RFunction pkgSkeleton(usingRcpp ?
                                       "Rcpp:::Rcpp.package.skeleton" :
                                       "utils:::package.skeleton");
      pkgSkeleton.addParam("name",
                           string_utils::utf8ToSystem(packageDir.filename()));
      pkgSkeleton.addParam("path",
               string_utils::utf8ToSystem(packageDir.parent().absolutePath()));
      pkgSkeleton.addParam("code_files", rFileNames);
      if (usingRcpp && module_context::haveRcppAttributes())
      {
         if (!cppFileNames.empty())
         {
            pkgSkeleton.addParam("example_code", false);
            pkgSkeleton.addParam("cpp_files", cppFileNames);
         }
         else
         {
            pkgSkeleton.addParam("attributes", true);
         }
      }
      error = pkgSkeleton.call();
      if (error)
         return error;

      // create the project file (allow auto-detection of the package
      // to setup the package build type & default options)
      r_util::RProjectConfig projConfig = ProjectContext::defaultConfig();
      return r_util::writeProjectFile(projectFilePath, projConfig);
   }
Error createProject(const json::JsonRpcRequest& request,
                    json::JsonRpcResponse* pResponse)
{
   // read params
   std::string projectFile;
   json::Value newPackageJson, newShinyAppJson;
   Error error = json::readParams(request.params,
                                  &projectFile,
                                  &newPackageJson,
                                  &newShinyAppJson);
   if (error)
      return error;
   FilePath projectFilePath = module_context::resolveAliasedPath(projectFile);

   // package project
   if (!newPackageJson.is_null())
   {
      // build list of code files
      bool usingRcpp;
      json::Array codeFilesJson;
      Error error = json::readObject(newPackageJson.get_obj(),
                                     "using_rcpp", &usingRcpp,
                                     "code_files", &codeFilesJson);
      if (error)
         return error;
      std::vector<FilePath> codeFiles;
      BOOST_FOREACH(const json::Value codeFile, codeFilesJson)
      {
         if (!json::isType<std::string>(codeFile))
         {
            BOOST_ASSERT(false);
            continue;
         }

         FilePath codeFilePath =
                     module_context::resolveAliasedPath(codeFile.get_str());
         codeFiles.push_back(codeFilePath);
      }

      // error if the package dir already exists
      FilePath packageDir = projectFilePath.parent();
      if (packageDir.exists())
         return core::fileExistsError(ERROR_LOCATION);

      // create a temp dir (so we can import the list of code files)
      FilePath tempDir = module_context::tempFile("newpkg", "dir");
      error = tempDir.ensureDirectory();
      if (error)
         return error;

      // copy the code files into the tempDir and build up a
      // list of the filenames for passing to package.skeleton
      std::vector<std::string> rFileNames, cppFileNames;
      BOOST_FOREACH(const FilePath& codeFilePath, codeFiles)
      {
         FilePath targetPath = tempDir.complete(codeFilePath.filename());
         Error error = codeFilePath.copy(targetPath);
         if (error)
            return error;

         std::string ext = targetPath.extensionLowerCase();
         std::string file = string_utils::utf8ToSystem(targetPath.filename());
         if (boost::algorithm::starts_with(ext,".c"))
            cppFileNames.push_back(file);
         else
            rFileNames.push_back(file);
      }