Improvements and refactoring of datadir handling

This commit is contained in:
Lukas Matena 2024-01-11 21:52:37 +01:00
parent 5bea4e7104
commit fbe63ba1ab
9 changed files with 185 additions and 192 deletions

View File

@ -62,6 +62,7 @@
#include "libslic3r/Thread.hpp" #include "libslic3r/Thread.hpp"
#include "libslic3r/BlacklistedLibraryCheck.hpp" #include "libslic3r/BlacklistedLibraryCheck.hpp"
#include "libslic3r/ProfilesSharingUtils.hpp" #include "libslic3r/ProfilesSharingUtils.hpp"
#include "libslic3r/Utils/DirectoriesUtils.hpp"
#include "PrusaSlicer.hpp" #include "PrusaSlicer.hpp"
@ -848,7 +849,10 @@ bool CLI::setup(int argc, char **argv)
for (const t_optiondef_map::value_type &optdef : *options) for (const t_optiondef_map::value_type &optdef : *options)
m_config.option(optdef.first, true); m_config.option(optdef.first, true);
set_data_dir(m_config.opt_string("datadir")); if (std::string provided_datadir = m_config.opt_string("datadir"); provided_datadir.empty()) {
set_data_dir(get_default_datadir());
} else
set_data_dir(provided_datadir);
//FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet.
if (!validity.empty()) { if (!validity.empty()) {
@ -962,13 +966,15 @@ std::set<std::string> query_options = {
bool CLI::processed_profiles_sharing() bool CLI::processed_profiles_sharing()
{ {
if (m_profiles_sharing.empty()) if (m_profiles_sharing.empty()) {
#if 0 // fsFIXME !!! just for the test #if 0 // fsFIXME !!! just for the test
DynamicPrintConfig config = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "Prusament PLA", "Original Prusa MINI & MINI+"); Slic3r::DynamicPrintConfig config = {};
bool was_loaded = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "Prusament PLA", "Original Prusa MINI & MINI+", config);
return true; return true;
#else #else
return false; return false;
#endif #endif
}
std::string ret; std::string ret;
for (auto const& opt_key : m_profiles_sharing) { for (auto const& opt_key : m_profiles_sharing) {
@ -986,9 +992,10 @@ bool CLI::processed_profiles_sharing()
ret = Slic3r::get_json_printer_profiles(m_config.opt_string("printer_model"), m_config.opt_string("printer_variant")); ret = Slic3r::get_json_printer_profiles(m_config.opt_string("printer_model"), m_config.opt_string("printer_variant"));
if (ret.empty()) if (ret.empty())
ret = "\nPrinter_model '" + m_config.opt_string("printer_model") + boost::nowide::cerr << "Printer_model '" << m_config.opt_string("printer_model") <<
"' with printer_variant '" + m_config.opt_string("printer_variant") + "' with printer_variant '" << m_config.opt_string("printer_variant") <<
"' wasn't found among intalled printers.\nOr the request can be wrong.\n"; "' wasn't found among installed printers." << std::endl <<
"Or the request can be wrong." << std::endl;
} }
*/ */
else if (opt_key == "query-print-filament-profiles") { else if (opt_key == "query-print-filament-profiles") {
@ -999,8 +1006,9 @@ bool CLI::processed_profiles_sharing()
ret = Slic3r::get_json_print_filament_profiles(m_config.opt_string("printer-profile")); ret = Slic3r::get_json_print_filament_profiles(m_config.opt_string("printer-profile"));
if (ret.empty()) if (ret.empty())
ret = "\nPrinter profile '" + m_config.opt_string("printer-profile") + boost::nowide::cerr << "Printer profile '" << m_config.opt_string("printer-profile") <<
"' wasn't found among intalled printers.\nOr the request can be wrong.\n"; "' wasn't found among installed printers." << std::endl <<
"Or the request can be wrong." << std::endl;
} }
else { else {
boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
@ -1013,9 +1021,9 @@ bool CLI::processed_profiles_sharing()
std::string cmdline_param = m_config.opt_string("output"); std::string cmdline_param = m_config.opt_string("output");
if (cmdline_param.empty()) { if (cmdline_param.empty()) {
if (ret.empty()) if (ret.empty())
printf("Wrong request"); boost::nowide::cerr << "Wrong request" << std::endl;
else else
printf(ret.c_str()); printf("%s", ret.c_str());
} }
else { else {
// if we were supplied a directory, use it and append our automatically generated filename // if we were supplied a directory, use it and append our automatically generated filename
@ -1034,9 +1042,7 @@ bool CLI::processed_profiles_sharing()
c << ret << std::endl; c << ret << std::endl;
c.close(); c.close();
printf("\nOutput for your request in written into \""); boost::nowide::cout << "Output for your request is written into " << file << std::endl;
printf(file.c_str());
printf("\"\n");
} }
return true; return true;

View File

@ -510,6 +510,8 @@ set(SLIC3R_SOURCES
StaticMap.hpp StaticMap.hpp
ProfilesSharingUtils.hpp ProfilesSharingUtils.hpp
ProfilesSharingUtils.cpp ProfilesSharingUtils.cpp
Utils/DirectoriesUtils.hpp
Utils/DirectoriesUtils.cpp
) )
if (APPLE) if (APPLE)

View File

@ -7,119 +7,25 @@
#include "format.hpp" #include "format.hpp"
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "Utils/DirectoriesUtils.hpp"
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
#if defined(_WIN32)
#include <shlobj.h>
static std::string GetDataDir()
{
HRESULT hr = E_FAIL;
std::wstring buffer;
buffer.resize(MAX_PATH);
hr = ::SHGetFolderPath
(
NULL, // parent window, not used
CSIDL_APPDATA,
NULL, // access token (current user)
SHGFP_TYPE_CURRENT, // current path, not just default value
(LPWSTR)buffer.data()
);
// somewhat incredibly, the error code in the Unicode version is
// different from the one in ASCII version for this function
#if wxUSE_UNICODE
if (hr == E_FAIL)
#else
if (hr == S_FALSE)
#endif
{
// directory doesn't exist, maybe we can get its default value?
hr = ::SHGetFolderPath
(
NULL,
CSIDL_APPDATA,
NULL,
SHGFP_TYPE_DEFAULT,
(LPWSTR)buffer.data()
);
}
for (int i=0; i< MAX_PATH; i++)
if (buffer.data()[i] == '\0') {
buffer.resize(i);
break;
}
return boost::nowide::narrow(buffer);
}
#elif defined(__linux__)
#include <stdlib.h>
#include <pwd.h>
static std::string GetDataDir()
{
std::string dir;
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);
}
dir += "/.config";
}
if (dir.empty())
printf("GetDataDir() > unsupported file layout \n");
return dir;
}
#endif
namespace Slic3r { namespace Slic3r {
static bool is_datadir() static bool load_preset_bundle_from_datadir(PresetBundle& preset_bundle)
{
if (!data_dir().empty())
return true;
const std::string config_dir = GetDataDir();
const std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string();
set_data_dir(data_dir);
return true;
}
static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle)
{ {
AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor); AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor);
if (!app_config.exists()) { if (!app_config.exists()) {
printf("Configuration wasn't found. Check your 'datadir' value.\n"); BOOST_LOG_TRIVIAL(error) << "Configuration wasn't found. Check your 'datadir' value.";
return false; return false;
} }
if (std::string error = app_config.load(); !error.empty()) { if (std::string error = app_config.load(); !error.empty()) {
throw Slic3r::RuntimeError(Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. " BOOST_LOG_TRIVIAL(error) << Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. "
"Try to manually delete the file to recover from the error. Your user profiles will not be affected." "Try to manually delete the file to recover from the error. Your user profiles will not be affected."
"\n\n%1%\n\n%2%", app_config.config_path(), error)); "\n%1%\n%2%", app_config.config_path(), error);
return false; return false;
} }
@ -133,7 +39,7 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle)
try { try {
auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
if (!preset_substitutions.empty()) { if (!preset_substitutions.empty()) {
printf("Some substitutions are found during loading presets.\n"); BOOST_LOG_TRIVIAL(error) << "Some substitutions are found during loading presets.";
return false; return false;
} }
@ -164,14 +70,13 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle)
vendor_profile.models = models; vendor_profile.models = models;
} }
} }
return true;
} }
catch (const std::exception& ex) { catch (const std::exception& ex) {
delayed_error_load_presets = ex.what(); BOOST_LOG_TRIVIAL(error) << ex.what();
printf(delayed_error_load_presets.c_str());
return false; return false;
} }
return true;
} }
namespace pt = boost::property_tree; namespace pt = boost::property_tree;
@ -228,7 +133,7 @@ std::string get_json_printer_profiles(const std::string& printer_model_name, con
PrinterAttr_ printer_attr({printer_model_name, printer_variant}); PrinterAttr_ printer_attr({printer_model_name, printer_variant});
PresetBundle preset_bundle; PresetBundle preset_bundle;
if (!load_preset_bandle_from_datadir(preset_bundle)) if (!load_preset_bundle_from_datadir(preset_bundle))
return ""; return "";
const VendorMap& vendors = preset_bundle.vendors; const VendorMap& vendors = preset_bundle.vendors;
@ -347,11 +252,8 @@ static void add_printer_models(pt::ptree& vendor_node,
std::string get_json_printer_models(PrinterTechnology printer_technology) std::string get_json_printer_models(PrinterTechnology printer_technology)
{ {
if (!is_datadir())
return "";
PresetBundle preset_bundle; PresetBundle preset_bundle;
if (!load_preset_bandle_from_datadir(preset_bundle)) if (!load_preset_bundle_from_datadir(preset_bundle))
return ""; return "";
pt::ptree vendor_node; pt::ptree vendor_node;
@ -440,11 +342,8 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle*
std::string get_json_print_filament_profiles(const std::string& printer_profile) std::string get_json_print_filament_profiles(const std::string& printer_profile)
{ {
if (!is_datadir())
return "";
PresetBundle preset_bundle; PresetBundle preset_bundle;
if (load_preset_bandle_from_datadir(preset_bundle)) { if (load_preset_bundle_from_datadir(preset_bundle)) {
const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false); const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false);
if (preset) if (preset)
return get_installed_print_and_filament_profiles(&preset_bundle, preset); return get_installed_print_and_filament_profiles(&preset_bundle, preset);
@ -454,39 +353,41 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile)
} }
// Helper function for FS // Helper function for FS
DynamicPrintConfig load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name) bool load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name, DynamicPrintConfig& config)
{ {
DynamicPrintConfig config = {}; PresetBundle preset_bundle;
if (!load_preset_bundle_from_datadir(preset_bundle)){
if (is_datadir()) { BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir());
PresetBundle preset_bundle; return false;
if (load_preset_bandle_from_datadir(preset_bundle)) {
config.apply(FullPrintConfig::defaults());
const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name);
if (print_preset)
config.apply_only(print_preset->config, print_preset->config.keys());
else
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name);
const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name);
if (filament_preset)
config.apply_only(filament_preset->config, filament_preset->config.keys());
else
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name);
const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name);
if (printer_preset)
config.apply_only(printer_preset->config, printer_preset->config.keys());
else
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name);
}
} }
else
BOOST_LOG_TRIVIAL(error) << "Datadir wasn't found\n";
return config; config = {};
config.apply(FullPrintConfig::defaults());
bool is_failed{ false };
if (const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name))
config.apply_only(print_preset->config, print_preset->config.keys());
else {
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name);
is_failed |= true;
}
if (const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name))
config.apply_only(filament_preset->config, filament_preset->config.keys());
else {
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name);
is_failed |= true;
}
if (const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name))
config.apply_only(printer_preset->config, printer_preset->config.keys());
else {
BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name);
is_failed |= true;
}
return !is_failed;
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -5,8 +5,6 @@
#ifndef slic3r_ProfilesSharingUtils_hpp_ #ifndef slic3r_ProfilesSharingUtils_hpp_
#define slic3r_ProfilesSharingUtils_hpp_ #define slic3r_ProfilesSharingUtils_hpp_
#include "libslic3r/PrintConfig.hpp"
namespace Slic3r { namespace Slic3r {
std::string get_json_printer_models(PrinterTechnology printer_technology); std::string get_json_printer_models(PrinterTechnology printer_technology);
@ -18,7 +16,8 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile)
std::string GetDataDir(); std::string GetDataDir();
#endif //__APPLE__ #endif //__APPLE__
DynamicPrintConfig load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset); class DynamicPrintConfig;
bool load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset, DynamicPrintConfig& out_config);
} // namespace Slic3r } // namespace Slic3r

View File

@ -0,0 +1,94 @@
#include "DirectoriesUtils.hpp"
#include "../libslic3r.h"
#include <boost/log/trivial.hpp>
#if defined(_WIN32)
#include <shlobj.h>
static std::string GetDataDir()
{
HRESULT hr = E_FAIL;
std::wstring buffer;
buffer.resize(MAX_PATH);
hr = ::SHGetFolderPathW
(
NULL, // parent window, not used
CSIDL_APPDATA,
NULL, // access token (current user)
SHGFP_TYPE_CURRENT, // current path, not just default value
(LPWSTR)buffer.data()
);
if (hr == E_FAIL)
{
// directory doesn't exist, maybe we can get its default value?
hr = ::SHGetFolderPathW
(
NULL,
CSIDL_APPDATA,
NULL,
SHGFP_TYPE_DEFAULT,
(LPWSTR)buffer.data()
);
}
for (int i=0; i< MAX_PATH; i++)
if (buffer.data()[i] == '\0') {
buffer.resize(i);
break;
}
return boost::nowide::narrow(buffer);
}
#elif defined(__linux__)
#include <stdlib.h>
#include <pwd.h>
static std::string GetDataDir()
{
std::string dir;
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);
}
if (! dir.empty())
dir += "/.config";
}
if (dir.empty())
BOOST_LOG_TRIVIAL(error) << "GetDataDir() > unsupported file layout";
return dir;
}
#endif
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();
return data_dir;
}
} // namespace Slic3r

View File

@ -0,0 +1,10 @@
#ifndef slic3r_DirectoriesUtils_hpp_
#define slic3r_DirectoriesUtils_hpp_
namespace Slic3r {
std::string get_default_datadir();
} // namespace Slic3r
#endif // slic3r_DirectoriesUtils_hpp_

View File

@ -16,9 +16,12 @@
#include "libslic3r_version.h" #include "libslic3r_version.h"
//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-alpha" //#define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY
//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-beta" #define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY "-alpha"
//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY "-beta"
#define GCODEVIEWER_APP_NAME "PrusaSlicer G-code Viewer" #define GCODEVIEWER_APP_NAME "PrusaSlicer G-code Viewer"
#define GCODEVIEWER_APP_KEY "PrusaSlicerGcodeViewer" #define GCODEVIEWER_APP_KEY "PrusaSlicerGcodeViewer"

View File

@ -63,6 +63,7 @@
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Color.hpp" #include "libslic3r/Color.hpp"
#include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" #include "libslic3r/Format/SLAArchiveFormatRegistry.hpp"
#include "libslic3r/Utils/DirectoriesUtils.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
@ -412,20 +413,14 @@ bool static check_old_linux_datadir(const wxString& app_name) {
// To be precise, the datadir should exist, it is created when single instance // To be precise, the datadir should exist, it is created when single instance
// lock happens. Instead of checking for existence, check the contents. // lock happens. Instead of checking for existence, check the contents.
namespace fs = boost::filesystem;
std::string new_path = Slic3r::data_dir(); std::string new_path = Slic3r::data_dir();
wxString dir; // If the config folder is redefined - do not check
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() ) // This happens when the user specifies a custom --datadir.
dir = wxFileName::GetHomeDir() + wxS("/.config"); if (new_path != get_default_datadir())
std::string default_path = (dir + "/" + app_name).ToUTF8().data();
if (new_path != default_path) {
// This happens when the user specifies a custom --datadir.
// Do not show anything in that case.
return true; return true;
}
namespace fs = boost::filesystem;
fs::path data_dir = fs::path(new_path); fs::path data_dir = fs::path(new_path);
if (! fs::is_directory(data_dir)) if (! fs::is_directory(data_dir))
@ -922,24 +917,8 @@ static boost::optional<Semver> parse_semver_from_ini(std::string path)
void GUI_App::init_app_config() void GUI_App::init_app_config()
{ {
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
SetAppName(SLIC3R_APP_FULL_NAME); SetAppName(SLIC3R_APP_FULL_NAME);
if (data_dir().empty()) {
#ifndef __linux__
set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data());
#else
// Since version 2.3, config dir on Linux is in ${XDG_CONFIG_HOME}.
// https://github.com/prusa3d/PrusaSlicer/issues/2911
wxString dir;
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
dir = wxFileName::GetHomeDir() + wxS("/.config");
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
#endif
} else {
m_datadir_redefined = true;
}
if (!app_config) if (!app_config)
app_config = new AppConfig(is_editor() ? AppConfig::EAppMode::Editor : AppConfig::EAppMode::GCodeViewer); app_config = new AppConfig(is_editor() ? AppConfig::EAppMode::Editor : AppConfig::EAppMode::GCodeViewer);
@ -970,7 +949,7 @@ std::string GUI_App::check_older_app_config(Semver current_version, bool backup)
std::string older_data_dir_path; std::string older_data_dir_path;
// If the config folder is redefined - do not check // If the config folder is redefined - do not check
if (m_datadir_redefined) if (data_dir() != get_default_datadir())
return {}; return {};
// find other version app config (alpha / beta / release) // find other version app config (alpha / beta / release)

View File

@ -418,7 +418,6 @@ private:
// inititate read of version file online in separate thread // inititate read of version file online in separate thread
void app_version_check(bool from_user); void app_version_check(bool from_user);
bool m_datadir_redefined { false };
bool m_wifi_config_dialog_shown { false }; bool m_wifi_config_dialog_shown { false };
}; };