Skip to content

Commit

Permalink
Merge branch 'feature/panmirror-dev' of https://github.com/rstudio/rs…
Browse files Browse the repository at this point in the history
…tudio into feature/panmirror-dev
  • Loading branch information
dragonstyle committed Sep 24, 2020
2 parents aafea21 + 4f80311 commit 99f947f
Show file tree
Hide file tree
Showing 27 changed files with 380 additions and 97 deletions.
25 changes: 16 additions & 9 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
* Multiple source panes can be opened in the main window via Global Options. (#2854)
* Keyboard shortcut `F6` added to navigate focus to the next pane. (#7408)

### Configurable Paths

* The user data folder `~/.rstudio` has been moved to `~/.local/share/rstudio`, and its location can now be customized with `XDG_DATA_HOME`. (#1846)
* `XDG_CONFIG_DIRS` can be used to specify alternate directories for server configuration files. (Pro #1607)
* It is now possible to specify the exact folder for user data and configuration files using new environment variables `RSTUDIO_DATA_HOME`, `RSTUDIO_CONFIG_DIR`, etc. (#7792)

### Miscellaneous

* The Files pane now sorts file names naturally, so that e.g. `step10.R` comes after `step9.R`. (#5766)
* Added command to File pane's "More" menu to copy path to clipboard (#6344)
* Table summaries are shown for `tibble` objects in R Notebooks. (#5970)
* The user data folder `~/.rstudio` has been moved to `~/.local/share/rstudio`, and its location can now be customized with `XDG_DATA_HOME`. (#1846)
* The font used in the editor and console can now be customized on RStudio Server. (#2534)
* `XDG_CONFIG_DIRS` can be used to specify alternate directories for server configuration files. (Pro #1607)
* The new option `www-same-site` provides support for the `SameSite` attribute on cookies issued by RStudio. (#6608)
* New `X-RStudio-Request` header for specifying originating URL behind path-rewriting proxies (Pro #1579)
* New `X-RStudio-Root-Path` header or the new `www-root-path` for specifying the exact path prefixes added by a path-rewriting proxy (Pro #1410).
* The option `www-url-path-prefix` was deprecated and removed. Use `www-root-path` instead.
* RStudio now infers document type from shebang (e.g. #!/usr/bin/env sh) for R, Python and shell scripts (#5643)
* New option to configure soft wrapping for R Markdown files, and command to change the soft wrap mode of the editor on the fly (#2341)
* New Command Palette for searching and running build-in commands and add-ins (#5168)
Expand All @@ -43,14 +42,22 @@
* Moved console options to a new pane in Global Options (#7047)
* The Data Viewer now uses the `format()` methods defined for columns entries when available (#7239)
* Add support for navigating source history with mouse forward/back buttons (#7272)
* Improved error logging of mistyped usernames when using PAM authentication (#7501)
* Add ability to go directly to various Global Option panes via Command Palette (#7678)
* R6Class method defintions are now indexed and accessible by the fuzzy finder (Ctrl + .)
* R6Class method definitions are now indexed and accessible by the fuzzy finder (Ctrl + .)
* The 'Preview' command for R documentation files now passes along RdMacros declared from the package DESCRIPTION file. (#6871)
* Some panes didn't have commands for making them visible, now they do (#5775)
* Show correct symbol for Return key in Mac menus (#6524)
* Added command and button for clearing Build pane output (#6636)

### RStudio Server

* The font used in the editor and console can now be customized on RStudio Server. (#2534)
* The new option `www-same-site` provides support for the `SameSite` attribute on cookies issued by RStudio. (#6608)
* New `X-RStudio-Request` header for specifying originating URL behind path-rewriting proxies (Pro #1579)
* New `X-RStudio-Root-Path` header or the new `www-root-path` for specifying the exact path prefixes added by a path-rewriting proxy (Pro #1410).
* The option `www-url-path-prefix` was deprecated and removed. Use `www-root-path` instead.
* Improved error logging of mistyped usernames when using PAM authentication (#7501)

### RStudio Server Pro

* SAML is now supported as an authentication mechanism (Pro #1194)
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/core/r_util/RSessionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ std::string SessionScope::workbench() const
else if (isVSCode())
return kWorkbenchVSCode;
else
return kWorkbenchJupyterNotebook;
return kWorkbenchRStudio;
}

// This function is intended to tell us whether a given path corresponds to an
Expand Down
6 changes: 6 additions & 0 deletions src/cpp/core/r_util/RUserData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ Error migrateUserStateIfNecessary(SessionType sessionType)
if (oldScratchPath.completeChildPath(kMigratedFile).exists())
return Success();

// If the new and old folders are the same, no migration is necessary (this
// could happen if RSTUDIO_DATA_HOME is used to preserve the legacy folder
// location)
if (oldScratchPath.isEquivalentTo(newPath))
return Success();

// Create the new folder if necessary so we can move content there.
error = newPath.ensureDirectory();
if (error)
Expand Down
147 changes: 119 additions & 28 deletions src/cpp/core/system/Xdg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <Windows.h>
#include <ShlObj_core.h>
#include <KnownFolders.h>
#include <winsock2.h>
#endif

#include <core/Algorithm.hpp>
Expand All @@ -25,14 +26,64 @@
#include <core/system/Environment.hpp>
#include <core/system/System.hpp>
#include <core/system/Xdg.hpp>
#include <core/Thread.hpp>

namespace rstudio {
namespace core {
namespace system {
namespace xdg {
namespace {

FilePath resolveXdgDir(const std::string& envVar,
/**
* Returns the hostname from the operating system
*/
std::string getHostname()
{
// Use a static string to store the hostname so we don't have to look it up
// multiple times
static std::string hostname;
static boost::mutex mutex;
std::string result;

// Lock to ensure that we don't try to read/write the hostname from two
// threads
LOCK_MUTEX(mutex)
{
if (hostname.empty())
{
char buffer[256];
int status = ::gethostname(buffer, 255);
if (status == 0)
{
// If successful, store the hostname for later; swallow errors here
// since they are not actionable
hostname = std::string(buffer);
}
}
result = hostname;
}
END_LOCK_MUTEX

return result;
}

/**
* Resolves an XDG directory based on the user and environment.
*
* @param rstudioEnvVer The RStudio-specific environment variable specifying
* the directory (given precedence)
* @param xdgEnvVar The XDG standard environment variable
* @param defaultDir Fallback default directory if neither environment variable
* is present
* @param windowsFolderId The ID of the Windows folder to resolve against
* @param user Optionally, the user to return a directory for; if omitted the
* current user is used
* @param homeDir Optionally, the home directory to resolve against; if omitted
* the current user's home directory is used
*/
FilePath resolveXdgDir(
const std::string& rstudioEnvVar,
const std::string& xdgEnvVar,
#ifdef _WIN32
const GUID windowsFolderId,
#endif
Expand All @@ -41,7 +92,18 @@ FilePath resolveXdgDir(const std::string& envVar,
const boost::optional<FilePath>& homeDir)
{
FilePath xdgHome;
std::string env = getenv(envVar);
bool finalPath = true;

// Look for the RStudio-specific environment variable
std::string env = getenv(rstudioEnvVar);
if (env.empty())
{
// The RStudio environment variable specifices the final path; if it isn't
// set we will need to append "rstudio" to the path later.
finalPath = false;
env = getenv(xdgEnvVar);
}

if (env.empty())
{
// No root specified for xdg home; we will need to generate one.
Expand Down Expand Up @@ -84,18 +146,36 @@ FilePath resolveXdgDir(const std::string& envVar,
xdgHome = FilePath(env);
}

// expand HOME and USER if given
// expand HOME, USER, and HOSTNAME if given
core::system::Options environment;
core::system::setenv(&environment, "HOME",
homeDir ? homeDir->getAbsolutePath() :
userHomePath().getAbsolutePath());
core::system::setenv(&environment, "USER",
user ? *user : username());

// check for manually specified hostname in environment variable
std::string hostname = core::system::getenv("HOSTNAME");

// when omitted, look up the hostname using a system call
if (hostname.empty())
{
hostname = getHostname();
}
core::system::setenv(&environment, "HOSTNAME", hostname);

std::string expanded = core::system::expandEnvVars(environment, xdgHome.getAbsolutePath());

// resolve aliases in the path
xdgHome = FilePath::resolveAliasedPath(expanded, homeDir ? *homeDir : userHomePath());

// If this is the final path, we can return it as-is
if (finalPath)
{
return xdgHome;
}

// Otherwise, it's a root folder in which we need to create our own subfolder
return xdgHome.completePath(
#ifdef _WIN32
"RStudio"
Expand All @@ -111,7 +191,8 @@ FilePath userConfigDir(
const boost::optional<std::string>& user,
const boost::optional<FilePath>& homeDir)
{
return resolveXdgDir("XDG_CONFIG_HOME",
return resolveXdgDir("RSTUDIO_CONFIG_HOME",
"XDG_CONFIG_HOME",
#ifdef _WIN32
FOLDERID_RoamingAppData,
#endif
Expand All @@ -125,7 +206,8 @@ FilePath userDataDir(
const boost::optional<std::string>& user,
const boost::optional<FilePath>& homeDir)
{
return resolveXdgDir("XDG_DATA_HOME",
return resolveXdgDir("RSTUDIO_DATA_HOME",
"XDG_DATA_HOME",
#ifdef _WIN32
FOLDERID_LocalAppData,
#endif
Expand All @@ -138,24 +220,28 @@ FilePath userDataDir(
FilePath systemConfigDir()
{
#ifndef _WIN32
// On POSIX operating systems, it's possible to specify multiple config directories.
// We have to select one, so read the list and take the first one that contains an
// "rstudio" folder.
std::string env = getenv("XDG_CONFIG_DIRS");
if (env.find_first_of(":") != std::string::npos)
if (getenv("RSTUDIO_CONFIG_DIR").empty())
{
std::vector<std::string> dirs = algorithm::split(env, ":");
for (const std::string& dir: dirs)
// On POSIX operating systems, it's possible to specify multiple config
// directories. We have to select one, so read the list and take the first
// one that contains an "rstudio" folder.
std::string env = getenv("XDG_CONFIG_DIRS");
if (env.find_first_of(":") != std::string::npos)
{
FilePath resolved = FilePath(dir).completePath("rstudio");
if (resolved.exists())
std::vector<std::string> dirs = algorithm::split(env, ":");
for (const std::string& dir: dirs)
{
return resolved;
FilePath resolved = FilePath(dir).completePath("rstudio");
if (resolved.exists())
{
return resolved;
}
}
}
}
#endif
return resolveXdgDir("XDG_CONFIG_DIRS",
return resolveXdgDir("RSTUDIO_CONFIG_DIR",
"XDG_CONFIG_DIRS",
#ifdef _WIN32
FOLDERID_ProgramData,
#endif
Expand All @@ -171,19 +257,22 @@ FilePath systemConfigFile(const std::string& filename)
// Passthrough on Windows
return systemConfigDir().completeChildPath(filename);
#else
// On POSIX, check for a search path.
std::string env = getenv("XDG_CONFIG_DIRS");
if (env.find_first_of(":") != std::string::npos)
if (getenv("RSTUDIO_CONFIG_DIR").empty())
{
// This is a search path; check each element for the file.
std::vector<std::string> dirs = algorithm::split(env, ":");
for (const std::string& dir: dirs)
// On POSIX, check for a search path.
std::string env = getenv("XDG_CONFIG_DIRS");
if (env.find_first_of(":") != std::string::npos)
{
FilePath resolved = FilePath(dir).completePath("rstudio")
.completeChildPath(filename);
if (resolved.exists())
// This is a search path; check each element for the file.
std::vector<std::string> dirs = algorithm::split(env, ":");
for (const std::string& dir: dirs)
{
return resolved;
FilePath resolved = FilePath(dir).completePath("rstudio")
.completeChildPath(filename);
if (resolved.exists())
{
return resolved;
}
}
}
}
Expand All @@ -197,8 +286,10 @@ FilePath systemConfigFile(const std::string& filename)
void forwardXdgEnvVars(Options *pEnvironment)
{
// forward relevant XDG environment variables (i.e. all those we respect above)
for (auto&& xdgVar: {"XDG_CONFIG_HOME", "XDG_CONFIG_DIRS",
"XDG_DATA_HOME", "XDG_DATA_DIRS"})
for (auto&& xdgVar: {"RSTUDIO_CONFIG_HOME", "RSTUDIO_CONFIG_DIR",
"RSTUDIO_DATA_HOME", "RSTUDIO_DATA_DIR",
"XDG_CONFIG_HOME", "XDG_CONFIG_DIRS",
"XDG_DATA_HOME", "XDG_DATA_DIRS"})
{
// only forward value if non-empty; avoid overwriting a previously set
// value with an empty one
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/server_core/ServerDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/

#include <server_core/ServerDatabase.hpp>
#include <server_core/ServerDatabaseKeyObfuscation.hpp>
#include <server_core/ServerKeyObfuscation.hpp>
#include <server_core/http/SecureCookie.hpp>

#include <boost/algorithm/string.hpp>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* ServerDatabaseKeyObfuscation.hpp
* ServerKeyObfuscation.hpp
*
* Copyright (C) 2020 by RStudio, PBC
*
Expand Down
13 changes: 11 additions & 2 deletions src/cpp/session/modules/rmarkdown/SessionRmdNotebook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,18 @@ void onChunkExecCompleted(const std::string& docId,
SEXP resultSEXP = R_NilValue;
std::string callback;

std::string escapedLabel =
core::string_utils::jsLiteralEscape(
core::string_utils::htmlEscape(label, true));
std::string escapedCode =
core::string_utils::jsLiteralEscape(
core::string_utils::htmlEscape(code, true));
boost::algorithm::replace_all(escapedLabel, "-", "_");
boost::algorithm::replace_all(escapedCode, "-", "_");

r::exec::RFunction func(".rs.executeChunkCallback");
func.addParam(label);
func.addParam(code);
func.addParam(escapedLabel);
func.addParam(escapedCode);

core::Error error = func.call(&resultSEXP, &rProtect);
if (error)
Expand Down
Loading

0 comments on commit 99f947f

Please sign in to comment.