Line data Source code
1 : /*! 2 : * \file esys/repo/userfolder.cpp 3 : * \brief 4 : * 5 : * \cond 6 : * __legal_b__ 7 : * 8 : * Copyright (c) 2023 Michel Gillet 9 : * Distributed under the MIT License. 10 : * (See accompanying file LICENSE.txt or 11 : * copy at https://opensource.org/licenses/MIT) 12 : * 13 : * __legal_e__ 14 : * \endcond 15 : * 16 : */ 17 : 18 : #include "esys/repo/esysrepo_prec.h" 19 : #include "esys/repo/userfolder.h" 20 : #include "esys/repo/userconfigfile.h" 21 : 22 : #ifdef WIN32 23 : #include <shlobj.h> 24 : #endif 25 : 26 : #include <boost/filesystem.hpp> 27 : #include <boost/locale.hpp> 28 : 29 : namespace esys::repo 30 : { 31 : 32 69 : UserFolder::UserFolder() = default; 33 : 34 138 : UserFolder::~UserFolder() = default; 35 : 36 79 : void UserFolder::set_path(const std::string &path) 37 : { 38 79 : m_path = path; 39 79 : } 40 : 41 0 : const std::string &UserFolder::get_path() const 42 : { 43 0 : return m_path; 44 : } 45 : 46 69 : void UserFolder::set_user_home_path(const std::string &user_home_path) 47 : { 48 69 : m_user_home_path = user_home_path; 49 69 : } 50 : 51 158 : const std::string &UserFolder::get_user_home_path() const 52 : { 53 158 : return m_user_home_path; 54 : } 55 : 56 79 : void UserFolder::set_user_config_file_path(const std::string &user_config_file_path) 57 : { 58 79 : m_user_config_file_path = user_config_file_path; 59 79 : } 60 : 61 58 : const std::string &UserFolder::get_user_config_file_path() const 62 : { 63 58 : return m_user_config_file_path; 64 : } 65 : 66 69 : void UserFolder::set_user_config(std::shared_ptr<UserConfig> user_config) 67 : { 68 69 : m_user_config = user_config; 69 69 : } 70 : 71 374 : std::shared_ptr<UserConfig> UserFolder::get_user_config() const 72 : { 73 374 : return m_user_config; 74 : } 75 : 76 0 : Result UserFolder::create_folder(const std::string &folder_path, bool ok_if_exists) 77 : { 78 0 : if (!boost::filesystem::exists(folder_path)) 79 : { 80 0 : bool result = boost::filesystem::create_directory(folder_path); 81 0 : if (!result) 82 : { 83 0 : error("The following folder couldn't be created : " + folder_path); 84 0 : return ESYSREPO_RESULT(ResultCode::FOLDER_CREATION_ERROR, folder_path); 85 : } 86 : else 87 0 : info("Created folder : " + folder_path); 88 : } 89 : else 90 : { 91 0 : if (!ok_if_exists) 92 : { 93 0 : error("The following folder already exits : " + folder_path); 94 0 : return ESYSREPO_RESULT(ResultCode::FOLDER_ALREADY_EXISTS, folder_path); 95 : } 96 : } 97 0 : return ESYSREPO_RESULT(ResultCode::OK); 98 : } 99 : 100 0 : Result UserFolder::create(bool ok_if_exists) 101 : { 102 0 : auto result = populate_all_pathes(); 103 0 : if (result.error()) return ESYSREPO_RESULT(result); 104 : 105 0 : if (get_user_config() == nullptr) ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 106 : 107 0 : result = create_folder(get_path(), ok_if_exists); 108 0 : if (result.error()) return ESYSREPO_RESULT(result); 109 : 110 0 : result = create_folder(get_user_config()->get_temp_path(), ok_if_exists); 111 0 : if (result.error()) return ESYSREPO_RESULT(result); 112 : 113 0 : result = create_folder(get_user_config()->get_manifest_directories_path(), ok_if_exists); 114 0 : if (result.error()) return ESYSREPO_RESULT(result); 115 : 116 0 : result = create_folder(get_user_config()->get_traces_path(), ok_if_exists); 117 0 : if (result.error()) return ESYSREPO_RESULT(result); 118 : 119 0 : UserConfigFile user_cfg_file; 120 0 : user_cfg_file.set_config(get_user_config()); 121 0 : result = user_cfg_file.write(get_user_config_file_path()); 122 0 : if (result.error()) return ESYSREPO_RESULT(result); 123 : 124 0 : return ESYSREPO_RESULT(ResultCode::OK); 125 0 : } 126 : 127 58 : Result UserFolder::read(const std::string &path, bool print_error) 128 : { 129 58 : boost::filesystem::path esysrepo_path = path; 130 : 131 58 : if (path.empty()) 132 : { 133 58 : auto result = populate_all_pathes(); 134 58 : if (result.error()) return ESYSREPO_RESULT(result); 135 58 : } 136 : else 137 : { 138 0 : if (!boost::filesystem::exists(path)) return ESYSREPO_RESULT(ResultCode::FILE_NOT_EXISTING, path); 139 : 140 0 : if (boost::filesystem::is_regular_file(esysrepo_path)) 141 0 : esysrepo_path = esysrepo_path.parent_path(); 142 0 : else if (boost::filesystem::is_directory(esysrepo_path)) 143 : { 144 0 : if (boost::filesystem::exists(esysrepo_path / ".esysrepo")) 145 0 : esysrepo_path /= ".esysrepo"; 146 0 : else if (esysrepo_path.filename() != ".esysrepo") 147 0 : return ESYSREPO_RESULT(ResultCode::FILE_NOT_EXISTING); 148 : } 149 : else 150 0 : return ESYSREPO_RESULT(ResultCode::GENERIC_ERROR); 151 : 152 0 : if (esysrepo_path.filename() == ".esysrepo") 153 0 : set_user_home_path(esysrepo_path.parent_path().string()); 154 : else 155 0 : return ESYSREPO_RESULT(ResultCode::FILE_NOT_EXISTING); 156 : 157 0 : auto result = populate_all_pathes(); 158 0 : if (result.error()) return ESYSREPO_RESULT(result); 159 0 : } 160 : 161 58 : UserConfigFile user_cfg_file; 162 58 : user_cfg_file.set_config(get_user_config()); 163 58 : auto result = user_cfg_file.read(get_user_config_file_path()); 164 58 : if (result.error()) return ESYSREPO_RESULT(result); 165 : 166 58 : return ESYSREPO_RESULT(ResultCode::OK); 167 116 : } 168 : 169 0 : Result UserFolder::write(const std::string &path) 170 : { 171 0 : auto result = populate_all_pathes(); 172 0 : if (result.error()) return ESYSREPO_RESULT(result); 173 : 174 0 : if (get_user_config() == nullptr) ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 175 : 176 0 : result = create_folder(get_path(), true); 177 0 : if (result.error()) return ESYSREPO_RESULT(result); 178 : 179 0 : if (boost::filesystem::exists(get_user_config_file_path())) 180 : { 181 0 : boost::filesystem::remove(get_user_config_file_path()); 182 : } 183 : 184 0 : UserConfigFile user_cfg_file; 185 0 : user_cfg_file.set_config(get_user_config()); 186 0 : result = user_cfg_file.write(get_user_config_file_path()); 187 0 : if (result.error()) return ESYSREPO_RESULT(result); 188 : 189 0 : return ESYSREPO_RESULT(ResultCode::OK); 190 0 : } 191 : 192 79 : Result UserFolder::populate_all_pathes() 193 : { 194 79 : if (get_user_home_path().empty()) 195 : { 196 69 : auto result = detect_home_folder(); 197 69 : if (result.error()) return ESYSREPO_RESULT(result); 198 69 : } 199 79 : boost::filesystem::path base_path = get_user_home_path(); 200 158 : boost::filesystem::path user_folder_path = base_path / ".esysrepo"; 201 158 : boost::filesystem::path temp_path = user_folder_path / "temp"; 202 158 : boost::filesystem::path user_config_file_path = user_folder_path / "user_config.xml"; 203 158 : boost::filesystem::path manifest_directories_path = user_folder_path / "manifest_directories"; 204 158 : boost::filesystem::path manifest_directories_file_path = user_folder_path / "manifest_directories.xml"; 205 158 : boost::filesystem::path traces_path = user_folder_path / "traces"; 206 : 207 79 : set_path(user_folder_path.string()); 208 79 : set_user_config_file_path(user_config_file_path.string()); 209 : 210 158 : if (get_user_config() == nullptr) set_user_config(std::make_shared<UserConfig>()); 211 : 212 79 : get_user_config()->set_temp_path(temp_path.string()); 213 79 : get_user_config()->set_manifest_directories_path(manifest_directories_path.string()); 214 79 : get_user_config()->set_traces_path(traces_path.string()); 215 : 216 79 : return ESYSREPO_RESULT(ResultCode::OK); 217 158 : } 218 : 219 69 : Result UserFolder::detect_home_folder() 220 : { 221 : #ifdef WIN32 222 : PWSTR path = nullptr; 223 : auto hresult = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &path); 224 : if (SUCCEEDED(hresult)) 225 : { 226 : auto char_path = boost::locale::conv::utf_to_utf<char>(path); 227 : set_user_home_path(char_path); 228 : CoTaskMemFree(path); 229 : return ESYSREPO_RESULT(ResultCode::OK); 230 : } 231 : else 232 : { 233 : CoTaskMemFree(path); 234 : return ESYSREPO_RESULT(ResultCode::GENERIC_ERROR); 235 : } 236 : #else 237 69 : auto path = std::getenv("XDG_CONFIG_HOME"); 238 69 : if (path != nullptr) 239 : { 240 0 : set_user_home_path(path); 241 0 : return ESYSREPO_RESULT(ResultCode::OK); 242 : } 243 69 : path = std::getenv("HOME"); 244 69 : if (path != nullptr) 245 : { 246 69 : set_user_home_path(path); 247 69 : return ESYSREPO_RESULT(ResultCode::OK); 248 : } 249 0 : return ESYSREPO_RESULT(ResultCode::GENERIC_ERROR); 250 : #endif 251 : } 252 : 253 : } // namespace esys::repo