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/BlacklistedLibraryCheck.hpp"
#include "libslic3r/ProfilesSharingUtils.hpp"
#include "libslic3r/Utils/DirectoriesUtils.hpp"
#include "PrusaSlicer.hpp"
@ -848,7 +849,10 @@ bool CLI::setup(int argc, char **argv)
for (const t_optiondef_map::value_type &optdef : *options)
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.
if (!validity.empty()) {
@ -962,13 +966,15 @@ std::set<std::string> query_options = {
bool CLI::processed_profiles_sharing()
{
if (m_profiles_sharing.empty())
if (m_profiles_sharing.empty()) {
#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;
#else
return false;
#endif
}
std::string ret;
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"));
if (ret.empty())
ret = "\nPrinter_model '" + m_config.opt_string("printer_model") +
"' with printer_variant '" + m_config.opt_string("printer_variant") +
"' wasn't found among intalled printers.\nOr the request can be wrong.\n";
boost::nowide::cerr << "Printer_model '" << m_config.opt_string("printer_model") <<
"' with printer_variant '" << m_config.opt_string("printer_variant") <<
"' wasn't found among installed printers." << std::endl <<
"Or the request can be wrong." << std::endl;
}
*/
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"));
if (ret.empty())
ret = "\nPrinter profile '" + m_config.opt_string("printer-profile") +
"' wasn't found among intalled printers.\nOr the request can be wrong.\n";
boost::nowide::cerr << "Printer profile '" << m_config.opt_string("printer-profile") <<
"' wasn't found among installed printers." << std::endl <<
"Or the request can be wrong." << std::endl;
}
else {
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");
if (cmdline_param.empty()) {
if (ret.empty())
printf("Wrong request");
boost::nowide::cerr << "Wrong request" << std::endl;
else
printf(ret.c_str());
printf("%s", ret.c_str());
}
else {
// 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.close();
printf("\nOutput for your request in written into \"");
printf(file.c_str());
printf("\"\n");
boost::nowide::cout << "Output for your request is written into " << file << std::endl;
}
return true;

View File

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

View File

@ -7,119 +7,25 @@
#include "format.hpp"
#include "PrintConfig.hpp"
#include "PresetBundle.hpp"
#include "Utils/DirectoriesUtils.hpp"
#include <boost/property_tree/json_parser.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
#include <boost/log/trivial.hpp>
namespace Slic3r {
static bool is_datadir()
{
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)
static bool load_preset_bundle_from_datadir(PresetBundle& preset_bundle)
{
AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor);
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;
}
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."
"\n\n%1%\n\n%2%", app_config.config_path(), error));
"\n%1%\n%2%", app_config.config_path(), error);
return false;
}
@ -133,7 +39,7 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle)
try {
auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
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;
}
@ -164,14 +70,13 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle)
vendor_profile.models = models;
}
}
return true;
}
catch (const std::exception& ex) {
delayed_error_load_presets = ex.what();
printf(delayed_error_load_presets.c_str());
BOOST_LOG_TRIVIAL(error) << ex.what();
return false;
}
return true;
}
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});
PresetBundle preset_bundle;
if (!load_preset_bandle_from_datadir(preset_bundle))
if (!load_preset_bundle_from_datadir(preset_bundle))
return "";
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)
{
if (!is_datadir())
return "";
PresetBundle preset_bundle;
if (!load_preset_bandle_from_datadir(preset_bundle))
if (!load_preset_bundle_from_datadir(preset_bundle))
return "";
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)
{
if (!is_datadir())
return "";
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);
if (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
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 = {};
if (is_datadir()) {
PresetBundle preset_bundle;
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);
}
PresetBundle preset_bundle;
if (!load_preset_bundle_from_datadir(preset_bundle)){
BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir());
return false;
}
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

View File

@ -5,8 +5,6 @@
#ifndef slic3r_ProfilesSharingUtils_hpp_
#define slic3r_ProfilesSharingUtils_hpp_
#include "libslic3r/PrintConfig.hpp"
namespace Slic3r {
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();
#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

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"
//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME
#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-alpha"
//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-beta"
// 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_KEY
#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_KEY "PrusaSlicerGcodeViewer"

View File

@ -63,6 +63,7 @@
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Color.hpp"
#include "libslic3r/Format/SLAArchiveFormatRegistry.hpp"
#include "libslic3r/Utils/DirectoriesUtils.hpp"
#include "GUI.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
// lock happens. Instead of checking for existence, check the contents.
namespace fs = boost::filesystem;
std::string new_path = Slic3r::data_dir();
wxString dir;
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
dir = wxFileName::GetHomeDir() + wxS("/.config");
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.
// If the config folder is redefined - do not check
// This happens when the user specifies a custom --datadir.
if (new_path != get_default_datadir())
return true;
}
namespace fs = boost::filesystem;
fs::path data_dir = fs::path(new_path);
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()
{
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
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)
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;
// If the config folder is redefined - do not check
if (m_datadir_redefined)
if (data_dir() != get_default_datadir())
return {};
// find other version app config (alpha / beta / release)

View File

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