diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 32ba6ca594..a6fa1d8522 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1624,6 +1624,7 @@ void PresetCollection::reset(bool delete_files) unlock(); m_map_alias_to_profile_name.clear(); m_map_system_profile_renamed.clear(); + m_unresolved_parents.clear(); } void PresetCollection::add_default_preset(const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name) @@ -1875,6 +1876,7 @@ void PresetCollection::load_presets( if (presets_loaded.empty()) { for (const auto &entry : deferred) { BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent %1% for config %2%!")%entry.second %entry.first.string(); + m_unresolved_parents[entry.first.string()] = entry.second; ++m_errors; } break; @@ -3345,6 +3347,16 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl return first_visible_if_not_found ? &this->first_visible() : nullptr; } +std::string PresetCollection::unresolved_parent(const boost::filesystem::path &file) const +{ + for (const auto &[dropped_file, parent] : m_unresolved_parents) { + boost::system::error_code ec; + if (boost::filesystem::equivalent(file, boost::filesystem::path(dropped_file), ec) && !ec) + return parent; + } + return {}; +} + Preset* PresetCollection::find_preset2(const std::string& name, bool auto_match/* = true */) { auto preset = find_preset(name, false, true); diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 6a7871d07d..86260d3432 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -2,6 +2,7 @@ #define slic3r_Preset_hpp_ #include +#include #include #include #include @@ -728,6 +729,9 @@ public: { return const_cast(this)->find_preset2(name, auto_match); } + // Name of the parent that kept the preset file from loading, or empty if the file loaded + // (or was never seen). Lets a caller that fails to find a preset explain why it is missing. + std::string unresolved_parent(const boost::filesystem::path &file) const; size_t first_visible_idx() const; // Return the index of the first visible, compatible, system base preset @@ -965,6 +969,8 @@ private: // Orca: used for validation only int m_errors = 0; + // Preset files dropped by load_presets() because their parent does not exist, keyed by file path. + std::map m_unresolved_parents; }; // Printer supports the FFF and SLA technologies, with different set of configuration values, diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index f17fd5c768..4d4fc1b9be 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -506,6 +506,11 @@ bool PresetBundle::resolve_preset_config(DynamicPrintConfig &config, Preset::Typ } if (error == "Preset identity is ambiguous") return false; + // The file was seen but dropped at load time; say so rather than reporting it as unknown. + if (const std::string parent = collection->unresolved_parent(source_path); !parent.empty()) { + error = "Preset was not loaded because its parent preset \"" + parent + "\" was not found"; + return false; + } if (!allow_source_manifest) { error = "Preset was not found in the loaded bundle"; return false; diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 18f2b5ac9f..bc797997e2 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -411,8 +411,8 @@ TEST_CASE("A preset whose parent exists nowhere is reported, not loaded", "[Pres ScopedTemporaryDir temp_dir; PresetBundle bundle; - write_sparse_preset(temp_dir.path() / PRESET_PRINT_NAME / "Orphan.json", "Orphan", "No Such Parent", - {{"layer_height", "0.15"}}); + const fs::path orphan_file = temp_dir.path() / PRESET_PRINT_NAME / "Orphan.json"; + write_sparse_preset(orphan_file, "Orphan", "No Such Parent", {{"layer_height", "0.15"}}); PresetsConfigSubstitutions substitutions; bundle.prints.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions, @@ -420,6 +420,14 @@ TEST_CASE("A preset whose parent exists nowhere is reported, not loaded", "[Pres CHECK(bundle.prints.find_preset("Orphan") == nullptr); CHECK(bundle.has_errors()); + CHECK(bundle.prints.unresolved_parent(orphan_file) == "No Such Parent"); + + // Resolving the dropped file names the missing parent instead of reporting the file as unknown. + DynamicPrintConfig config; + std::string error; + CHECK_FALSE(bundle.resolve_preset_config(config, Preset::TYPE_PRINT, orphan_file.string(), + ForwardCompatibilitySubstitutionRule::Disable, error, false)); + CHECK(error == "Preset was not loaded because its parent preset \"No Such Parent\" was not found"); } TEST_CASE("Presets inheriting each other in a cycle are reported, not loaded", "[Preset][Inherits][Regression]")