From 03e0957f21a035c773beff1db907faee1a3e8a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Tue, 12 Nov 2024 17:01:07 +0100 Subject: [PATCH] Improve config dir detection. - Specific to linux. - If the current config dir is not $HOME/.config dir check the $HOME/.config dir for previous existing configs. - Targeted on flatpak where the config dir is configured using $XDG_CONFIG_HOME and is not in $HOME, where it will trigger a prompt for config migration. --- src/libslic3r/Utils/DirectoriesUtils.cpp | 65 +++++++++++++-------- src/libslic3r/Utils/DirectoriesUtils.hpp | 5 ++ src/slic3r/GUI/GUI_App.cpp | 72 ++++++++++++++++++++---- 3 files changed, 107 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/Utils/DirectoriesUtils.cpp b/src/libslic3r/Utils/DirectoriesUtils.cpp index 3c3f07aa00..d0ab335271 100644 --- a/src/libslic3r/Utils/DirectoriesUtils.cpp +++ b/src/libslic3r/Utils/DirectoriesUtils.cpp @@ -51,34 +51,51 @@ static std::string GetDataDir() #include #include -static std::string GetDataDir() -{ - std::string dir; +std::optional get_env(std::string_view key) { + const char* result{getenv(key.data())}; + if(result == nullptr) { + return std::nullopt; + } + return std::string{result}; +} - char* ptr; - if ((ptr = getenv("XDG_CONFIG_HOME"))) - dir = std::string(ptr); - else { - if ((ptr = getenv("HOME"))) - dir = std::string(ptr); - else { - struct passwd* who = (struct passwd*)NULL; - if ((ptr = getenv("USER")) || (ptr = getenv("LOGNAME"))) - who = getpwnam(ptr); - // make sure the user exists! - if (!who) - who = getpwuid(getuid()); - - dir = std::string(who ? who->pw_dir : 0); +namespace Slic3r { +std::optional get_home_config_dir() { + if (auto result{get_env("HOME")}) { + return *result + "/.config"; + } else { + std::optional user_name{get_env("USER")}; + if (!user_name) { + user_name = get_env("LOGNAME"); } - if (! dir.empty()) - dir += "/.config"; + struct passwd* who{ + user_name ? + getpwnam(user_name->data()) : + (struct passwd*)NULL + }; + // make sure the user exists! + if (!who) { + who = getpwuid(getuid()); + } + if (who) { + return std::string{who->pw_dir} + "/.config"; + } + } + return std::nullopt; +} +} + +std::string GetDataDir() +{ + if (auto result{get_env("XDG_CONFIG_HOME")}) { + return *result; + } else if (auto result{Slic3r::get_home_config_dir()}) { + return result->string(); } - if (dir.empty()) - BOOST_LOG_TRIVIAL(error) << "GetDataDir() > unsupported file layout"; + BOOST_LOG_TRIVIAL(error) << "GetDataDir() > unsupported file layout"; - return dir; + return {}; } #endif @@ -88,7 +105,7 @@ namespace Slic3r { std::string get_default_datadir() { const std::string config_dir = GetDataDir(); - const std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string(); + std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string(); return data_dir; } diff --git a/src/libslic3r/Utils/DirectoriesUtils.hpp b/src/libslic3r/Utils/DirectoriesUtils.hpp index cafc054708..f6ded98630 100644 --- a/src/libslic3r/Utils/DirectoriesUtils.hpp +++ b/src/libslic3r/Utils/DirectoriesUtils.hpp @@ -2,6 +2,8 @@ #define slic3r_DirectoriesUtils_hpp_ #include +#include +#include #if __APPLE__ //implemented at MacUtils.mm @@ -10,6 +12,9 @@ std::string GetDataDir(); namespace Slic3r { +// Only defined on linux. +std::optional get_home_config_dir(); + std::string get_default_datadir(); } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a79d6dbc2f..15d2d5cd49 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1071,6 +1071,58 @@ void GUI_App::legacy_app_config_vendor_check() copy_vendor_ini(vendors_to_create); } +std::array get_possible_app_names() { + const std::array suffixes{"-alpha", "-beta", ""}; + std::array result; + std::transform( + suffixes.begin(), + suffixes.end(), + result.begin(), + [](const std::string &suffix){ + return SLIC3R_APP_KEY + suffix; + } + ); + return result; +} + +constexpr bool is_linux = +#if defined(__linux__) +true +#else +false +#endif +; + +namespace fs = boost::filesystem; + +std::vector get_app_config_dir_candidates( + const std::string ¤t_app_name +) { + std::vector candidates; + + // e.g. $HOME/.config + const fs::path config_dir{fs::path{data_dir()}.parent_path()}; + const std::array possible_app_names{get_possible_app_names()}; + + for (const std::string &possible_app_name : possible_app_names){ + if (possible_app_name != current_app_name) { + candidates.emplace_back(config_dir / possible_app_name); + } + } + + if constexpr (is_linux) { + const std::optional home_config_dir{get_home_config_dir()}; + if (home_config_dir && config_dir != home_config_dir) { + for (const std::string &possible_app_name : possible_app_names){ + candidates.emplace_back(*home_config_dir / possible_app_name); + } + } + } + + return candidates; +} + + // returns old config path to copy from if such exists, // returns an empty string if such config path does not exists or if it cannot be loaded. std::string GUI_App::check_older_app_config(Semver current_version, bool backup) @@ -1082,22 +1134,20 @@ std::string GUI_App::check_older_app_config(Semver current_version, bool backup) return {}; // find other version app config (alpha / beta / release) - std::string config_path = app_config->config_path(); - boost::filesystem::path parent_file_path(config_path); - std::string filename = parent_file_path.filename().string(); - parent_file_path.remove_filename().remove_filename(); + const fs::path app_config_path{app_config->config_path()}; + const std::string filename{app_config_path.filename().string()}; - std::vector candidates; - - if (SLIC3R_APP_KEY "-alpha" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-alpha" / filename); - if (SLIC3R_APP_KEY "-beta" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-beta" / filename); - if (SLIC3R_APP_KEY != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY / filename); + const std::string current_app_name{GetAppName().ToStdString()}; + const std::vector app_config_dir_candidates{get_app_config_dir_candidates( + current_app_name + )}; Semver last_semver = current_version; - for (const auto& candidate : candidates) { + for (const fs::path& candidate_dir : app_config_dir_candidates) { + const fs::path candidate{candidate_dir / filename}; if (boost::filesystem::exists(candidate)) { // parse - boost::optionalother_semver = parse_semver_from_ini(candidate.string()); + const boost::optionalother_semver = parse_semver_from_ini(candidate.string()); if (other_semver && *other_semver > last_semver) { last_semver = *other_semver; older_data_dir_path = candidate.parent_path().string();