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.
This commit is contained in:
Martin Šach 2024-11-12 17:01:07 +01:00 committed by Lukas Matena
parent 7cc94a31e5
commit 03e0957f21
3 changed files with 107 additions and 35 deletions

View File

@ -51,34 +51,51 @@ static std::string GetDataDir()
#include <stdlib.h>
#include <pwd.h>
static std::string GetDataDir()
{
std::string dir;
std::optional<std::string> 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<boost::filesystem::path> get_home_config_dir() {
if (auto result{get_env("HOME")}) {
return *result + "/.config";
} else {
std::optional<std::string> 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;
}

View File

@ -2,6 +2,8 @@
#define slic3r_DirectoriesUtils_hpp_
#include <string>
#include <boost/filesystem.hpp>
#include <optional>
#if __APPLE__
//implemented at MacUtils.mm
@ -10,6 +12,9 @@ std::string GetDataDir();
namespace Slic3r {
// Only defined on linux.
std::optional<boost::filesystem::path> get_home_config_dir();
std::string get_default_datadir();
} // namespace Slic3r

View File

@ -1071,6 +1071,58 @@ void GUI_App::legacy_app_config_vendor_check()
copy_vendor_ini(vendors_to_create);
}
std::array<std::string, 3> get_possible_app_names() {
const std::array<std::string, 3> suffixes{"-alpha", "-beta", ""};
std::array<std::string, 3> 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<fs::path> get_app_config_dir_candidates(
const std::string &current_app_name
) {
std::vector<fs::path> candidates;
// e.g. $HOME/.config
const fs::path config_dir{fs::path{data_dir()}.parent_path()};
const std::array<std::string, 3> 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<fs::path> 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<boost::filesystem::path> 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<fs::path> 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::optional<Semver>other_semver = parse_semver_from_ini(candidate.string());
const boost::optional<Semver>other_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();