1 /*
2  * RVersions.hpp
3  *
4  * Copyright (C) 2021 by RStudio, PBC
5  *
6  * Unless you have received this program directly from RStudio pursuant
7  * to the terms of a commercial license agreement with RStudio, then
8  * this program is licensed to you under the terms of version 3 of the
9  * GNU Affero General Public License. This program is distributed WITHOUT
10  * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12  * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13  *
14  */
15 
16 #ifndef CORE_R_UTIL_R_VERSIONS_HPP
17 #define CORE_R_UTIL_R_VERSIONS_HPP
18 
19 #define kRStudioRVersionsPath "RS_R_VERSIONS_PATH"
20 
21 #include <vector>
22 #include <iosfwd>
23 
24 #include <shared_core/FilePath.hpp>
25 
26 #include <shared_core/json/Json.hpp>
27 
28 #include <core/system/Environment.hpp>
29 
30 #include <core/r_util/RVersionInfo.hpp>
31 
32 namespace rstudio {
33 namespace core {
34 namespace r_util {
35 
36 class RVersion
37 {
38 public:
RVersion()39    RVersion() {}
RVersion(const std::string & number,const core::system::Options & environment)40    RVersion(const std::string& number, const core::system::Options& environment)
41       : number_(number), environment_(environment)
42    {
43       setLabel(std::string());
44       setModule(std::string());
45       setPrelaunchScript(std::string());
46       setRepo(std::string());
47       setLibrary(std::string());
48    }
49 
50 public:
empty() const51    bool empty() const { return number_.empty(); }
52 
homeDir() const53    FilePath homeDir() const
54    {
55       return FilePath(core::system::getenv(environment_, "R_HOME"));
56    }
57 
setHomeDir(const FilePath & filePath)58    void setHomeDir(const FilePath& filePath)
59    {
60       core::system::setenv(&environment_, "R_HOME", filePath.getAbsolutePath());
61    }
62 
number() const63    const std::string& number() const { return number_; }
setNumber(const std::string & number)64    void setNumber(const std::string& number) { number_ = number; }
65 
environment() const66    const core::system::Options& environment() const { return environment_; }
setEnvironment(const core::system::Options & environment)67    void setEnvironment(const core::system::Options& environment) { environment_ = environment; }
68 
label() const69    const std::string& label() const { return label_; }
setLabel(const std::string & label)70    void setLabel(const std::string& label)
71    {
72       label_ = label;
73       core::system::setenv(&environment_, "RSTUDIO_R_VERSION_LABEL", label);
74    }
75 
module() const76    const std::string& module() const { return module_; }
setModule(const std::string & module)77    void setModule(const std::string& module)
78    {
79       module_ = module;
80       core::system::setenv(&environment_, "RSTUDIO_R_MODULE", module);
81    }
82 
prelaunchScript() const83    const std::string& prelaunchScript() const { return prelaunchScript_; }
setPrelaunchScript(const std::string & prelaunchScript)84    void setPrelaunchScript(const std::string& prelaunchScript)
85    {
86       prelaunchScript_ = prelaunchScript;
87       core::system::setenv(&environment_, "RSTUDIO_R_PRELAUNCH_SCRIPT", prelaunchScript);
88    }
89 
repo() const90    const std::string& repo() const { return repo_; }
setRepo(const std::string & repo)91    void setRepo(const std::string& repo)
92    {
93       repo_ = repo;
94       core::system::setenv(&environment_, "RSTUDIO_R_REPO", repo);
95    }
96 
library() const97    const std::string& library() const { return library_; }
setLibrary(const std::string & library)98    void setLibrary(const std::string& library)
99    {
100       library_ = library;
101 
102       // only set R_LIBS_SITE env var if it is non-empty
103       // setting an empty site library will cause the default system configuration to be lost
104       if (!library.empty())
105          core::system::setenv(&environment_, "R_LIBS_SITE", library);
106    }
107 
operator <(const RVersion & other) const108    bool operator<(const RVersion& other) const
109    {
110       RVersionNumber ver = RVersionNumber::parse(number());
111       RVersionNumber otherVer = RVersionNumber::parse(other.number());
112 
113       if (ver == otherVer)
114          return homeDir().getAbsolutePath() < other.homeDir().getAbsolutePath();
115       else
116          return ver < otherVer;
117    }
118 
operator ==(const RVersion & other) const119    bool operator==(const RVersion& other) const
120    {
121       return number() == other.number() &&
122          homeDir().getAbsolutePath() == other.homeDir().getAbsolutePath() &&
123              (label() == other.label() || (label().empty() || other.label().empty()));
124    }
125 
126 private:
127    std::string number_;
128    core::system::Options environment_;
129    std::string label_;
130    std::string module_;
131    std::string prelaunchScript_;
132    std::string repo_;
133    std::string library_;
134 };
135 
136 std::ostream& operator<<(std::ostream& os, const RVersion& version);
137 
138 std::vector<RVersion> enumerateRVersions(
139                               std::vector<FilePath> rHomePaths,
140                               std::vector<r_util::RVersion> rEntries,
141                               bool scanForOtherVersions,
142                               const FilePath& ldPathsScript,
143                               const std::string& ldLibraryPath,
144                               const FilePath& modulesBinaryPath);
145 
146 RVersion selectVersion(const std::string& number,
147                        const std::string& rHomeDir,
148                        const std::string& label,
149                        std::vector<RVersion> versions);
150 
151 json::Object rVersionToJson(const r_util::RVersion& version);
152 
153 r_util::RVersion rVersionFromJson(const json::Object& versionJson);
154 
155 Error rVersionsFromJson(const json::Array& versionsJson,
156                         std::vector<RVersion>* pVersions);
157 
158 json::Array versionsToJson(const std::vector<r_util::RVersion>& versions);
159 
160 Error writeRVersionsToFile(const FilePath& filePath,
161                           const std::vector<r_util::RVersion>& versions);
162 
163 Error readRVersionsFromFile(const FilePath& filePath,
164                             std::vector<r_util::RVersion>* pVersions);
165 
166 Error validatedReadRVersionsFromFile(const FilePath& filePath,
167                                      std::vector<r_util::RVersion>* pVersions);
168 
169 } // namespace r_util
170 } // namespace core
171 } // namespace rstudio
172 
173 #endif // CORE_R_UTIL_R_VERSIONS_HPP
174 
175