void saveWorkingContext(const FilePath& statePath, Settings* pSettings, bool* pSaved) { // save history FilePath historyPath = statePath.complete(kHistoryFile); Error error = consoleHistory().saveToFile(historyPath); if (error) { reportError(kSaving, kHistoryFile, error, ERROR_LOCATION); *pSaved = false; } // save client metrics client_metrics::save(pSettings); // save aliased path to current working directory std::string workingDirectory = FilePath::createAliasedPath( utils::safeCurrentPath(), r::session::utils::userHomePath()); pSettings->set(kWorkingDirectory, workingDirectory); // save console actions FilePath consoleActionsPath = statePath.complete(kConsoleActionsFile); error = consoleActions().saveToFile(consoleActionsPath); if (error) { reportError(kSaving, kConsoleActionsFile, error, ERROR_LOCATION); *pSaved = false; } }
FilePath rBinaryPath() { FilePath binPath = FilePath(R_HomeDir()).complete("bin"); #ifdef _WIN32 return binPath.complete("Rterm.exe"); #else return binPath.complete("R"); #endif }
FilePath Options::urlopenerPath() const { FilePath parentDir = scriptsPath(); // detect dev configuration if (parentDir.filename() == "desktop") parentDir = parentDir.complete("urlopener"); return parentDir.complete("urlopener.exe"); }
FilePath Options::rsinversePath() const { FilePath parentDir = scriptsPath(); // detect dev configuration if (parentDir.filename() == "desktop") parentDir = parentDir.complete("synctex/rsinverse"); return parentDir.complete("rsinverse.exe"); }
FilePath Options::wwwDocsPath() const { FilePath supportingFilePath = desktop::options().supportingFilePath(); FilePath wwwDocsPath = supportingFilePath.complete("www/docs"); if (!wwwDocsPath.exists()) wwwDocsPath = supportingFilePath.complete("../gwt/www/docs"); #ifdef __APPLE__ if (!wwwDocsPath.exists()) wwwDocsPath = supportingFilePath.complete("../../../../../gwt/www/docs"); #endif return wwwDocsPath; }
FilePath texFilePath(const std::string& logPath, const FilePath& compileDir) { // some tex compilers report file names with absolute paths and some // report them relative to the compilation directory -- on Posix use // realPath to get a clean full path back -- note the fact that we // don't do this on Windows is a tacit assumption that Windows TeX logs // are either absolute or don't require interpretation of .., etc. FilePath path = compileDir.complete(logPath); #ifdef _WIN32 return path; #else FilePath realPath; Error error = core::system::realPath(path.absolutePath(), &realPath); if (error) { LOG_ERROR(error); return path; } else { return realPath; } #endif }
Error detectZipFileOverwrites(const FilePath& uploadedZipFile, const FilePath& destDir, json::Array* pOverwritesJson) { // query for all of the paths in the zip file std::vector<std::string> zipFileListing; r::exec::RFunction listZipFile(".rs.listZipFile", uploadedZipFile.absolutePath()); Error unzipError = listZipFile.call(&zipFileListing); if (unzipError) return unzipError; // check for overwrites for (std::vector<std::string>::const_iterator it = zipFileListing.begin(); it != zipFileListing.end(); ++it) { FilePath filePath = destDir.complete(*it); if (filePath.exists()) pOverwritesJson->push_back(module_context::createFileSystemItem(filePath)); } return Success(); }
void handleHelpHomeRequest(const core::http::Request& request, const std::string& jsCallbacks, core::http::Response* pResponse) { // get the resource path FilePath helpResPath = options().rResourcesPath().complete("help_resources"); // resolve the file reference std::string path = http::util::pathAfterPrefix(request, "/help/doc/home/"); // if it's empty then this is the root template if (path.empty()) { std::map<std::string,std::string> variables; variables["js_callbacks"] = jsCallbacks; text::TemplateFilter templateFilter(variables); pResponse->setNoCacheHeaders(); pResponse->setFile(helpResPath.childPath("index.htm"), request, templateFilter); } // otherwise it's just a file reference else { FilePath filePath = helpResPath.complete(path); pResponse->setCacheableFile(filePath, request); } }
Error UserSettings::initialize() { // calculate settings file path FilePath settingsDir = module_context::registerMonitoredUserScratchDir( "user-settings", boost::bind(&UserSettings::onSettingsFileChanged, this, _1)); settingsFilePath_ = settingsDir.complete("user-settings"); // if it doesn't exist see if we can migrate an old user settings if (!settingsFilePath_.exists()) { FilePath oldSettingsPath = module_context::userScratchPath().complete("user-settings"); if (oldSettingsPath.exists()) oldSettingsPath.move(settingsFilePath_); } // read the settings Error error = settings_.initialize(settingsFilePath_); if (error) return error; // make sure we have a context id if (contextId().empty()) setContextId(core::system::generateUuid()); return Success(); }
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent, Qt::Dialog), ui(new Ui::AboutDialog()) { ui->setupUi(this); ui->buttonBox->addButton(new QPushButton(QString::fromUtf8("OK")), QDialogButtonBox::AcceptRole); ui->lblIcon->setPixmap(QPixmap(QString::fromUtf8(":/icons/resources/freedesktop/icons/64x64/rstudio.png"))); ui->lblVersion->setText(QString::fromUtf8( "Version " RSTUDIO_VERSION " - © 2009-2012 RStudio, Inc.")); setWindowModality(Qt::ApplicationModal); // read notice file FilePath supportingFilePath = options().supportingFilePath(); FilePath noticePath = supportingFilePath.complete("NOTICE"); std::string notice; Error error = readStringFromFile(noticePath, ¬ice); if (!error) { ui->textBrowser->setFontFamily(options().fixedWidthFont()); #ifdef Q_OS_MAC ui->textBrowser->setFontPointSize(11); #else ui->textBrowser->setFontPointSize(9); #endif ui->textBrowser->setText(QString::fromUtf8(notice.c_str())); } }
bool copySourceFile(const FilePath& sourceDir, const FilePath& destDir, int level, const FilePath& sourceFilePath) { // compute the target path std::string relativePath = sourceFilePath.relativePath(sourceDir); FilePath targetPath = destDir.complete(relativePath); // if the copy item is a directory just create it if (sourceFilePath.isDirectory()) { Error error = targetPath.ensureDirectory(); if (error) LOG_ERROR(error); } // otherwise copy it else { Error error = sourceFilePath.copy(targetPath); if (error) LOG_ERROR(error); } return true; }
void RestartContext::initialize(const FilePath& scopePath, const std::string& contextId) { FilePath contextsPath = restartContextsPath(scopePath); FilePath statePath = contextsPath.complete(kContext + contextId); if (statePath.exists()) sessionStatePath_ = statePath; }
FilePath RestartContext::createSessionStatePath(const FilePath& scopePath, const std::string& contextId) { FilePath contextsPath = restartContextsPath(scopePath); FilePath statePath = contextsPath.complete(kContext + contextId); Error error = statePath.ensureDirectory(); if (error) LOG_ERROR(error); return statePath; }
bool prepareEnvironment(Options& options) { // check for which R override FilePath rWhichRPath; std::string whichROverride = ::core::system::getenv("RSTUDIO_WHICH_R"); if (!whichROverride.empty()) rWhichRPath = FilePath(whichROverride); // determine rLdPaths script location FilePath supportingFilePath = options.supportingFilePath(); FilePath rLdScriptPath = supportingFilePath.complete("bin/r-ldpath"); if (!rLdScriptPath.exists()) rLdScriptPath = supportingFilePath.complete("session/r-ldpath"); // attempt to detect R environment std::string rScriptPath, rVersion, errMsg; r_util::EnvironmentVars rEnvVars; bool success = r_util::detectREnvironment(rWhichRPath, rLdScriptPath, std::string(), &rScriptPath, &rVersion, &rEnvVars, &errMsg); if (!success) { showRNotFoundError(errMsg); return false; } if (desktop::options().runDiagnostics()) { std::cout << std::endl << "Using R script: " << rScriptPath << std::endl; } // set environment and return true r_util::setREnvironmentVars(rEnvVars); return true; }
Error PersistentState::initialize() { serverMode_ = (session::options().programMode() == kSessionProgramModeServer); // always the same so that we can supporrt a restart of // the session without reloading the client page desktopClientId_ = "33e600bb-c1b1-46bf-b562-ab5cba070b0e"; FilePath scratchPath = module_context::scopedScratchPath(); FilePath statePath = scratchPath.complete("persistent-state"); return settings_.initialize(statePath); }
Error currentViewerSourcePath(FilePath* pSourcePath) { // determine source path module_context::ViewerHistoryEntry viewerEntry = viewerHistory().current(); if (viewerEntry.empty()) { return systemError(boost::system::errc::invalid_argument, ERROR_LOCATION); } FilePath tempPath = module_context::tempDir(); *pSourcePath = tempPath.complete(viewerEntry.sessionTempPath()); return Success(); }
void initSaveContext(const FilePath& statePath, Settings* pSettings, bool* pSaved) { // ensure the context exists Error error = statePath.ensureDirectory(); if (error) { reportError(kSaving, "creating directory", error, ERROR_LOCATION); *pSaved = false; } // init session settings error = pSettings->initialize(statePath.complete(kSettingsFile)); if (error) { reportError(kSaving, kSettingsFile, error, ERROR_LOCATION); *pSaved = false; } }
// installation path Error installPath(const std::string& relativeToExecutable, int argc, char * const argv[], FilePath* pInstallPath) { #if defined(__APPLE__) // get path to current executable uint32_t buffSize = 2048; std::vector<char> buffer(buffSize); if (_NSGetExecutablePath(&(buffer[0]), &buffSize) == -1) { buffer.resize(buffSize); _NSGetExecutablePath(&(buffer[0]), &buffSize); } // calculate install path return installPath(&(buffer[0]), relativeToExecutable, pInstallPath); #elif defined(HAVE_PROCSELF) // calcluate install path return installPath("/proc/self/exe", relativeToExecutable, pInstallPath); #else // Note that this technique will NOT work if the executable was located // via a search of the PATH. To make this fallback fully robust we would // need to also search the PATH for the exe name in argv[0] // // use argv[0] and initial path FilePath initialPath = FilePath::initialPath(); std::string exePath = initialPath.complete(argv[0]).absolutePath(); // calculate install path return installPath(exePath, relativeToExecutable, pInstallPath); #endif }
Error executablePath(const char * argv0, FilePath* pExecutablePath) { std::string executablePath; #if defined(__APPLE__) // get path to current executable uint32_t buffSize = 2048; std::vector<char> buffer(buffSize); if (_NSGetExecutablePath(&(buffer[0]), &buffSize) == -1) { buffer.resize(buffSize); _NSGetExecutablePath(&(buffer[0]), &buffSize); } // set it executablePath = std::string(&(buffer[0])); #elif defined(HAVE_PROCSELF) executablePath = std::string("/proc/self/exe"); #else // Note that this technique will NOT work if the executable was located // via a search of the PATH. To make this fallback fully robust we would // need to also search the PATH for the exe name in argv[0] // // use argv[0] and initial path FilePath initialPath = FilePath::initialPath(); executablePath = initialPath.complete(argv0).absolutePath(); #endif // return realPath of executable path return realPath(executablePath, pExecutablePath); }
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); }
int main(int argc, char* argv[]) { core::system::initHook(); try { initializeLang(); if (useChromiumDevtools()) { // use QTcpSocket to find an open port. this is unfortunately a bit racey // but AFAICS there isn't a better solution for port selection QByteArray port; QTcpSocket* pSocket = new QTcpSocket(); if (pSocket->bind()) { quint16 port = pSocket->localPort(); desktopInfo().setChromiumDevtoolsPort(port); core::system::setenv("QTWEBENGINE_REMOTE_DEBUGGING", safe_convert::numberToString(port)); pSocket->close(); } } // initialize log core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, desktop::userLogPath()); // ignore SIGPIPE Error error = core::system::ignoreSignal(core::system::SigPipe); if (error) LOG_ERROR(error); // attempt to remove stale lockfiles, as they can impede // application startup error = removeStaleOptionsLockfile(); if (error) LOG_ERROR(error); // set application attributes QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // prepare command line arguments static std::vector<char*> arguments(argv, argv + argc); // enable viewport meta (allows us to control / restrict // certain touch gestures) static char enableViewport[] = "--enable-viewport"; arguments.push_back(enableViewport); #ifndef NDEBUG // disable web security for development builds (so we can // get access to sourcemaps) static char disableWebSecurity[] = "--disable-web-security"; arguments.push_back(disableWebSecurity); #endif // disable chromium renderer accessibility by default (it can cause // slowdown when used in conjunction with some applications; see e.g. // https://github.com/rstudio/rstudio/issues/1990) if (core::system::getenv("RSTUDIO_ACCESSIBILITY").empty()) { static char disableRendererAccessibility[] = "--disable-renderer-accessibility"; arguments.push_back(disableRendererAccessibility); } #ifdef Q_OS_LINUX // workaround for Qt 5.10.1 bug "Could not find QtWebEngineProcess" // https://bugreports.qt.io/browse/QTBUG-67023 // https://bugreports.qt.io/browse/QTBUG-66346 static char noSandbox[] = "--no-sandbox"; arguments.push_back(noSandbox); #endif #ifdef Q_OS_MAC // don't prefer compositing to LCD text rendering. when enabled, this causes the compositor to // be used too aggressively on Retina displays on macOS, with the side effect that the // scrollbar doesn't auto-hide because a compositor layer is present. // https://github.com/rstudio/rstudio/issues/1953 static char disableCompositorPref[] = "--disable-prefer-compositing-to-lcd-text"; arguments.push_back(disableCompositorPref); // disable gpu rasterization for certain display configurations. // this works around some of the rendering issues seen with RStudio. // // https://bugs.chromium.org/p/chromium/issues/detail?id=773705 // https://github.com/rstudio/rstudio/issues/2093 // // because the issue seems to only affect certain video cards on macOS // High Sierra, we scope that change to that particular configuration // for now (we can expand this list if more users report issues) core::Version macVersion(QSysInfo::productVersion().toStdString()); if (macVersion.versionMajor() == 10 && macVersion.versionMinor() == 13) { core::system::ProcessResult processResult; core::system::runCommand( "/usr/sbin/system_profiler SPDisplaysDataType", core::system::ProcessOptions(), &processResult); std::string stdOut = processResult.stdOut; if (!stdOut.empty()) { std::vector<std::string> blackList = { "NVIDIA GeForce GT 650M", "NVIDIA GeForce GT 750M" }; for (const std::string& entry : blackList) { if (stdOut.find(entry) != std::string::npos) { static char disableGpuRasterization[] = "--disable-gpu-rasterization"; arguments.push_back(disableGpuRasterization); break; } } } } #endif // re-assign command line arguments argc = (int) arguments.size(); argv = &arguments[0]; // prepare application for launch boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromUtf8("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) { QString arg = pApp->arguments().at(1); if (arg != QString::fromUtf8(kRunDiagnosticsOption)) filename = verifyAndNormalizeFilename(arg); } } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } // init options from command line desktop::options().initFromCommandLine(pApp->arguments()); // reset log if we are in run-diagnostics mode if (desktop::options().runDiagnostics()) { desktop::reattachConsoleIfNecessary(); initializeStderrLog("rdesktop", core::system::kLogLevelWarning); } initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; error = core::system::installPath("..", argv[0], &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file, rsession, and desktop scripts FilePath confPath, sessionPath, scriptsPath; bool devMode = false; // check for debug configuration FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); scriptsPath = currentPath.complete("desktop"); devMode = true; #ifdef _WIN32 if (version.architecture() == ArchX64 && installPath.complete("session/x64").exists()) { sessionPath = installPath.complete("session/x64/rsession"); } #endif } // if there is no conf path then release mode if (confPath.empty()) { // default paths (then tweak) sessionPath = installPath.complete("bin/rsession"); scriptsPath = installPath.complete("bin"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64 && installPath.complete("bin/x64").exists()) { sessionPath = installPath.complete("bin/x64/rsession"); } #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) { sessionPath = installPath.complete("MacOS/rsession"); scriptsPath = installPath.complete("MacOS"); } #endif } core::system::fixupExecutablePath(&sessionPath); auto* pProxyFactory = new NetworkProxyFactory(); QNetworkProxyFactory::setApplicationProxyFactory(pProxyFactory); // set the scripts path in options desktop::options().setScriptsPath(scriptsPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath, filename, pAppLaunch.get()); sessionLauncher.launchFirstSession(installPath, devMode, pApp->arguments()); ProgressActivator progressActivator; int result = pApp->exec(); desktop::activation().releaseLicense(); options.cleanUpScratchTempDir(); return result; } CATCH_UNEXPECTED_EXCEPTION }
void onDocSaved(FilePath &path) { Error error; // ignore non-R Markdown saves if (!path.hasExtensionLowerCase(".rmd")) return; // find cache folder (bail out if it doesn't exist) FilePath cache = chunkCacheFolder(path, "", notebookCtxId()); if (!cache.exists()) return; FilePath saved = chunkCacheFolder(path, "", kSavedCtx); if (saved.exists()) { // tidy up: remove any saved chunks that no longer exist error = removeStaleSavedChunks(path, saved); if (error) LOG_ERROR(error); } else { // no saved context yet; ensure we have a place to put it saved.ensureDirectory(); } // move all the chunk definitions over to the saved context std::vector<FilePath> children; error = cache.children(&children); if (error) { LOG_ERROR(error); return; } BOOST_FOREACH(const FilePath source, children) { // compute the target path FilePath target = saved.complete(source.filename()); if (source.filename() == kNotebookChunkDefFilename) { // the definitions should be copied (we always want them in both // contexts) error = target.removeIfExists(); if (!error) error = source.copy(target); } else if (source.isDirectory()) { // library folders should be merged and then removed, so we don't // lose library contents if (source.filename() == kChunkLibDir) { error = mergeLib(source, target); if (!error) error = source.remove(); } else { // the chunk output folders should be moved; destroy the old copy error = target.removeIfExists(); if (!error) error = source.move(target); } } else { // nothing besides the chunks.json and chunk folders should be here, // so ignore other files/content continue; } if (error) LOG_ERROR(error); }
void handleMultipleFileExportRequest(const http::Request& request, http::Response* pResponse) { // name parameter std::string name = request.queryParamValue("name"); if (name.empty()) { pResponse->setError(http::status::BadRequest, "name not specified"); return; } // parent parameter std::string parent = request.queryParamValue("parent"); if (parent.empty()) { pResponse->setError(http::status::BadRequest, "parent not specified"); return; } FilePath parentPath = module_context::resolveAliasedPath(parent); if (!parentPath.exists()) { pResponse->setError(http::status::BadRequest, "parent doesn't exist"); return; } // files parameters (paths relative to parent) std::vector<std::string> files; for (int i=0; ;i++) { // get next file (terminate when we stop finding files) std::string fileParam = "file" + boost::lexical_cast<std::string>(i); std::string file = request.queryParamValue(fileParam); if (file.empty()) break; // verify that the file exists FilePath filePath = parentPath.complete(file); if (!filePath.exists()) { pResponse->setError(http::status::BadRequest, "file " + file + " doesn't exist"); return; } // add it files.push_back(file); } // create the zip file FilePath tempZipFilePath = module_context::tempFile("export", "zip"); Error error = r::exec::RFunction(".rs.createZipFile", tempZipFilePath.absolutePath(), parentPath.absolutePath(), files).call(); if (error) { LOG_ERROR(error); pResponse->setError(error); return; } // return attachment setAttachmentResponse(request, name, tempZipFilePath, pResponse); }
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; }
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); }
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; }
void Options::resolvePath(const FilePath& resourcePath, std::string* pPath) { if (!pPath->empty()) *pPath = resourcePath.complete(*pPath).absolutePath(); }
int main(int argc, char* argv[]) { core::system::initHook(); try { QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); // initialize log FilePath userHomePath = core::system::userHomePath("R_USER|HOME"); FilePath logPath = core::system::userSettingsPath( userHomePath, "RStudio-Desktop").childPath("log"); core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, logPath); boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromAscii("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) filename = verifyAndNormalizeFilename(pApp->arguments().last()); } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } pApp->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; Error error = core::system::installPath("..", argc, argv, &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file and rsession FilePath confPath, sessionPath; // check for debug configuration #ifndef NDEBUG FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("x64/rsession"); #endif } #endif // if there is no conf path then release mode if (confPath.empty()) { // default session path (then tweak) sessionPath = installPath.complete("bin/rsession"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("bin/x64/rsession"); #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) sessionPath = installPath.complete("MacOS/rsession"); #endif } core::system::fixupExecutablePath(&sessionPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath); error = sessionLauncher.launchFirstSession(filename, pAppLaunch.get()); if (!error) { int result = pApp->exec(); sessionLauncher.cleanupAtExit(); options.cleanUpScratchTempDir(); return result; } else { LOG_ERROR(error); // These calls to processEvents() seem to be necessary to get // readAllStandardError to work. pApp->processEvents(); pApp->processEvents(); pApp->processEvents(); QMessageBox errorMsg(safeMessageBoxIcon(QMessageBox::Critical), QString::fromUtf8("RStudio"), sessionLauncher.launchFailedErrorMessage()); errorMsg.addButton(new QPushButton(QString::fromUtf8("OK")), QMessageBox::AcceptRole); errorMsg.show(); pApp->exec(); return EXIT_FAILURE; } } CATCH_UNEXPECTED_EXCEPTION }
int main(int argc, char* argv[]) { core::system::initHook(); try { initializeLang(); // initialize log core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, desktop::userLogPath()); // ignore SIGPIPE Error error = core::system::ignoreSignal(core::system::SigPipe); if (error) LOG_ERROR(error); #ifdef __APPLE__ // font substituion for OSX Mavericks // see: https://bugreports.qt-project.org/browse/QTBUG-32789 QFont::insertSubstitution(QString::fromUtf8(".Lucida Grande UI"), QString::fromUtf8("Lucida Grande")); #endif boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromUtf8("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) { QString arg = pApp->arguments().last(); if (arg != QString::fromUtf8(kRunDiagnosticsOption)) filename = verifyAndNormalizeFilename(arg); } } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } // init options from command line desktop::options().initFromCommandLine(pApp->arguments()); // reset log if we are in run-diagnostics mode if (desktop::options().runDiagnostics()) { desktop::reattachConsoleIfNecessary(); initializeStderrLog("rdesktop", core::system::kLogLevelWarning); } pApp->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; error = core::system::installPath("..", argv[0], &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file, rsession, and desktop scripts FilePath confPath, sessionPath, scriptsPath; // check for debug configuration #ifndef NDEBUG FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); scriptsPath = currentPath.complete("desktop"); #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("x64/rsession"); #endif } #endif // if there is no conf path then release mode if (confPath.empty()) { // default paths (then tweak) sessionPath = installPath.complete("bin/rsession"); scriptsPath = installPath.complete("bin"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("bin/x64/rsession"); #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) { sessionPath = installPath.complete("MacOS/rsession"); scriptsPath = installPath.complete("MacOS"); } #endif } core::system::fixupExecutablePath(&sessionPath); // set the scripts path in options desktop::options().setScriptsPath(scriptsPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath); error = sessionLauncher.launchFirstSession(filename, pAppLaunch.get()); if (!error) { int result = pApp->exec(); sessionLauncher.cleanupAtExit(); options.cleanUpScratchTempDir(); return result; } else { LOG_ERROR(error); // These calls to processEvents() seem to be necessary to get // readAllStandardError to work. pApp->processEvents(); pApp->processEvents(); pApp->processEvents(); QMessageBox errorMsg(safeMessageBoxIcon(QMessageBox::Critical), QString::fromUtf8("RStudio"), sessionLauncher.launchFailedErrorMessage()); errorMsg.addButton(new QPushButton(QString::fromUtf8("OK")), QMessageBox::AcceptRole); errorMsg.show(); pApp->exec(); return EXIT_FAILURE; } } CATCH_UNEXPECTED_EXCEPTION }