fix: old preset names should resolved renamed_from field (#14429)
* fix: old preset names should resolved renamed_from field * chore: remove misleading comments * Merge branch 'main' into fix/consider_renamed_from * normalize_inherits * improve find_preset2 performace
This commit is contained in:
@@ -1672,6 +1672,7 @@ void PresetCollection::load_presets(
|
||||
std::string inherits_value = option_str->value;
|
||||
// Orca: try to find if the parent preset has been renamed
|
||||
inherit_preset = this->find_preset2(inherits_value);
|
||||
Preset::normalize_inherits(config, inherit_preset);
|
||||
} else {
|
||||
;
|
||||
}
|
||||
@@ -1924,6 +1925,7 @@ void PresetCollection::load_project_embedded_presets(std::vector<Preset*>& proje
|
||||
option_str->value = inherits_value;
|
||||
}*/
|
||||
inherit_preset = this->find_preset2(inherits_value, true);
|
||||
Preset::normalize_inherits(config, inherit_preset);
|
||||
}
|
||||
const Preset& default_preset = this->default_preset_for(config);
|
||||
if (inherit_preset) {
|
||||
@@ -2260,6 +2262,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
ConfigOptionString * option_str = dynamic_cast<ConfigOptionString *> (inherits_config);
|
||||
std::string inherits_value = option_str->value;
|
||||
inherit_preset = this->find_preset2(inherits_value, true);
|
||||
Preset::normalize_inherits(cloud_config, inherit_preset);
|
||||
}
|
||||
const Preset& default_preset = this->default_preset_for(cloud_config);
|
||||
if (inherit_preset) {
|
||||
@@ -2674,7 +2677,10 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
||||
preset.filament_id = filament_id;
|
||||
else {
|
||||
if (!inherits.empty()) {
|
||||
Preset *parent = this->find_preset(inherits, false, true);
|
||||
// Orca: resolve via find_preset2 so a renamed/removed-and-matched parent still
|
||||
// yields its filament_id (external presets store a full config, so the dangling
|
||||
// "inherits" itself is normalized on the next load_presets pass).
|
||||
Preset *parent = this->find_preset2(inherits, true);
|
||||
if (parent)
|
||||
preset.filament_id = parent->filament_id;
|
||||
}
|
||||
@@ -2938,10 +2944,14 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
//BBS: only save difference for user preset
|
||||
Preset* parent_preset = nullptr;
|
||||
if (!final_inherits.empty()) {
|
||||
parent_preset = this->find_preset(final_inherits, false, true);
|
||||
if (parent_preset && this->get_selected_preset().base_id.empty()) {
|
||||
this->get_selected_preset().base_id = parent_preset->setting_id;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " base_id: " << parent_preset->setting_id;
|
||||
parent_preset = this->find_preset2(final_inherits, true);
|
||||
if (parent_preset) {
|
||||
// Orca: take the saved diff against the resolved parent (renamed / library-matched).
|
||||
Preset::normalize_inherits(this->get_selected_preset().config, parent_preset);
|
||||
if (this->get_selected_preset().base_id.empty()) {
|
||||
this->get_selected_preset().base_id = parent_preset->setting_id;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " base_id: " << parent_preset->setting_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parent_preset)
|
||||
@@ -3053,14 +3063,8 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
||||
return nullptr;
|
||||
preset = &this->default_preset(m_type == Preset::Type::TYPE_PRINTER && edited_preset.printer_technology() == ptSLA ? 1 : 0);
|
||||
} else
|
||||
// find_preset() already resolves "renamed_from" internally.
|
||||
preset = this->find_preset(inherits, false);
|
||||
if (preset == nullptr) {
|
||||
// Resolve the "renamed_from" field.
|
||||
assert(! inherits.empty());
|
||||
auto it = this->find_preset_renamed(inherits);
|
||||
if (it != m_presets.end())
|
||||
preset = &(*it);
|
||||
}
|
||||
//BBS: add project embedded preset logic and refine is_external
|
||||
return (preset == nullptr/* || preset->is_default || preset->is_external*/) ? nullptr : preset;
|
||||
//return (preset == nullptr/* || preset->is_default*/ || preset->is_external) ? nullptr : preset;
|
||||
@@ -3072,12 +3076,8 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
if (inherits.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
return nullptr;
|
||||
// find_preset() already resolves "renamed_from" internally.
|
||||
const Preset* preset = this->find_preset(inherits, false);
|
||||
if (preset == nullptr) {
|
||||
auto it = this->find_preset_renamed(inherits);
|
||||
if (it != m_presets.end())
|
||||
preset = &(*it);
|
||||
}
|
||||
return
|
||||
// not found
|
||||
(preset == nullptr/* || preset->is_default */||
|
||||
@@ -3176,6 +3176,14 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl
|
||||
auto it = this->find_preset_internal(canonical, only_from_library);
|
||||
if (it != m_presets.end() && it->name == canonical)
|
||||
return &this->preset(it - m_presets.begin(), real);
|
||||
// Resolve the "renamed_from" field: a system preset may have been renamed (e.g. by a
|
||||
// vendor profile sync), which records its old name in "renamed_from". Try the rename
|
||||
// map before the first-visible fallback so every caller - including those passing
|
||||
// real/only_from_library or first_visible_if_not_found - resolves to the renamed preset
|
||||
// rather than a mismatched one. Recursion follows multi-step renames (A->B->C) and
|
||||
// terminates as soon as a name resolves or has no further rename entry.
|
||||
if (const std::string* renamed = get_preset_name_renamed(name))
|
||||
return find_preset(*renamed, first_visible_if_not_found, real, only_from_library);
|
||||
return first_visible_if_not_found ? &this->first_visible() : nullptr;
|
||||
}
|
||||
|
||||
@@ -3183,14 +3191,11 @@ Preset* PresetCollection::find_preset2(const std::string& name, bool auto_match/
|
||||
{
|
||||
auto preset = find_preset(name, false, true);
|
||||
if (preset == nullptr) {
|
||||
auto _name = get_preset_name_renamed(name);
|
||||
if (_name != nullptr)
|
||||
preset = find_preset(*_name, false, true);
|
||||
if (auto_match && preset == nullptr) {
|
||||
if (auto_match) {
|
||||
//Orca: one more try, find the most likely preset in OrcaFilamentLibrary
|
||||
if (name.find("Generic") != std::string::npos) {
|
||||
// The regex pattern matches an optional prefix ending in '_' then "Generic" followed by the material name.
|
||||
std::regex re(R"(^(?:.*?\b(?:\w+_)?)(Generic)\b\s+([^@]+?)\s*(?:@.*)?$)");
|
||||
static const std::regex re(R"(^(?:.*?\b(?:\w+_)?)(Generic)\b\s+([^@]+?)\s*(?:@.*)?$)");
|
||||
auto alter_name = std::regex_replace(name, re, "Generic $2 @System");
|
||||
preset = find_preset2(alter_name, false);
|
||||
// print preset file name
|
||||
|
||||
@@ -320,6 +320,20 @@ public:
|
||||
std::string& inherits() { return Preset::inherits(this->config); }
|
||||
const std::string& inherits() const { return Preset::inherits(const_cast<Preset*>(this)->config); }
|
||||
|
||||
// Rewrite cfg's "inherits" to the resolved parent's canonical name. find_preset2 may
|
||||
// resolve a renamed parent, or a removed vendor profile auto-matched to the
|
||||
// OrcaFilamentLibrary; persisting the canonical name lets later plain find_preset()
|
||||
// callers (e.g. get_preset_parent) walk the inheritance chain without the fuzzy match.
|
||||
// No-op when the parent could not be resolved or the name is already canonical.
|
||||
static void normalize_inherits(DynamicPrintConfig &cfg, const Preset *resolved_parent)
|
||||
{
|
||||
if (resolved_parent == nullptr)
|
||||
return;
|
||||
std::string &inherits = Preset::inherits(cfg);
|
||||
if (inherits != resolved_parent->name)
|
||||
inherits = resolved_parent->name;
|
||||
}
|
||||
|
||||
// Returns the "compatible_prints_condition".
|
||||
static std::string& compatible_prints_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_prints_condition", true)->value; }
|
||||
std::string& compatible_prints_condition() {
|
||||
|
||||
@@ -1498,6 +1498,9 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
ConfigOptionString *option_str = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
inherits_value = option_str->value;
|
||||
inherit_preset = collection->find_preset2(inherits_value, true);
|
||||
Preset::normalize_inherits(config, inherit_preset);
|
||||
if (inherit_preset)
|
||||
inherits_value = inherit_preset->name; // keep the base_id redo below in sync
|
||||
}
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
@@ -1869,6 +1872,8 @@ bool PresetBundle::save_preset_to_bundle_dir(Preset& preset, PresetCollection* c
|
||||
if (!parent_preset) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " cannot find parent preset for " << preset.name << ", inherits " << inherits;
|
||||
} else {
|
||||
// Orca: take the saved diff against the resolved parent (renamed / library-matched).
|
||||
Preset::normalize_inherits(preset.config, parent_preset);
|
||||
if (preset.base_id.empty())
|
||||
preset.base_id = parent_preset->setting_id;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " saved preset " << preset.name
|
||||
|
||||
@@ -1876,12 +1876,6 @@ void ConfigWizard::priv::load_vendors()
|
||||
for (auto &bundle : bundles) {
|
||||
const PresetCollection &materials = bundle.second.preset_bundle->materials(technology);
|
||||
const Preset *preset = materials.find_preset(material_name);
|
||||
if (preset == nullptr) {
|
||||
// Not found. Maybe the material preset is there, bu it was was renamed?
|
||||
const std::string *new_name = materials.get_preset_name_renamed(material_name);
|
||||
if (new_name != nullptr)
|
||||
preset = materials.find_preset(*new_name);
|
||||
}
|
||||
if (preset != nullptr) {
|
||||
// Materal preset was found, mark it as installed.
|
||||
section_new[preset->name] = "true";
|
||||
|
||||
@@ -36,6 +36,47 @@ void write_print_preset(const DynamicPrintConfig &default_config, const fs::path
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
}
|
||||
|
||||
// Write a preset json carrying a name and an "inherits" value, using the given collection's
|
||||
// default config so it loads back into that collection. Works for any preset type.
|
||||
void write_preset_with_inherits(const DynamicPrintConfig &default_config, const fs::path &file,
|
||||
const std::string &name, const std::string &inherits)
|
||||
{
|
||||
DynamicPrintConfig config(default_config);
|
||||
config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = inherits;
|
||||
|
||||
fs::create_directories(file.parent_path());
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
}
|
||||
|
||||
// Add an in-memory preset (no file) with the given inherits value (empty => root preset).
|
||||
Preset &add_inmemory_preset(PresetCollection &coll, const std::string &name, const std::string &inherits = {})
|
||||
{
|
||||
DynamicPrintConfig config(coll.default_preset().config);
|
||||
config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = inherits;
|
||||
return coll.load_preset(std::string(), name, config, /*select=*/false);
|
||||
}
|
||||
|
||||
// Mark an already-loaded preset as renamed from one or more former names.
|
||||
void set_renamed_from(PresetCollection &coll, const std::string &preset_name, std::vector<std::string> old_names)
|
||||
{
|
||||
for (auto it = coll.begin(); it != coll.end(); ++it)
|
||||
if (it->name == preset_name)
|
||||
it->renamed_from = std::move(old_names);
|
||||
}
|
||||
|
||||
// A standalone print preset collection that exposes the protected rename-map builder, so a
|
||||
// renamed_from scenario can be set up without the full system-profile load pipeline.
|
||||
// (PresetCollection is non-copyable - it holds a mutex - so it is constructed directly with
|
||||
// the same type/keys/defaults PresetBundle uses for its print collection.)
|
||||
struct RenameTestCollection : public PresetCollection
|
||||
{
|
||||
RenameTestCollection()
|
||||
: PresetCollection(Preset::TYPE_PRINT, Preset::print_options(),
|
||||
static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()))
|
||||
{}
|
||||
using PresetCollection::update_map_system_profile_renamed;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]")
|
||||
@@ -130,3 +171,130 @@ TEST_CASE("Printer extruder count tolerates missing nozzle diameter", "[Preset][
|
||||
CHECK(bundle.get_printer_extruder_count() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset resolves a system preset's renamed_from", "[Preset][Rename]")
|
||||
{
|
||||
RenameTestCollection coll;
|
||||
|
||||
// "New Process" is the current preset; it was renamed from "Old Process".
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// The rename map knows the old name...
|
||||
const std::string *renamed = coll.get_preset_name_renamed("Old Process");
|
||||
REQUIRE(renamed != nullptr);
|
||||
CHECK(*renamed == "New Process");
|
||||
|
||||
// ...and plain find_preset() now follows it (the core of this PR; previously this
|
||||
// resolution lived only in find_preset2 and a few call sites).
|
||||
const Preset *resolved = coll.find_preset("Old Process");
|
||||
REQUIRE(resolved != nullptr);
|
||||
CHECK(resolved->name == "New Process");
|
||||
|
||||
// A genuinely unknown name still returns null (no spurious match).
|
||||
CHECK(coll.find_preset("Totally Unknown") == nullptr);
|
||||
|
||||
// A child that still inherits the OLD name resolves through the runtime walker,
|
||||
// which uses plain find_preset().
|
||||
Preset &child = add_inmemory_preset(coll, "Child Process", "Old Process");
|
||||
const Preset *parent = coll.get_preset_parent(child);
|
||||
REQUIRE(parent != nullptr);
|
||||
CHECK(parent->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset resolves a preset renamed more than once", "[Preset][Rename]")
|
||||
{
|
||||
RenameTestCollection coll;
|
||||
|
||||
// "New Process" was renamed twice, so it carries both former names in renamed_from.
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Original Process", "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// Each historical name resolves to the current preset.
|
||||
for (const char *old_name : { "Original Process", "Old Process" }) {
|
||||
INFO("resolving old name: " << old_name);
|
||||
const std::string *renamed = coll.get_preset_name_renamed(old_name);
|
||||
REQUIRE(renamed != nullptr);
|
||||
CHECK(*renamed == "New Process");
|
||||
|
||||
const Preset *resolved = coll.find_preset(old_name);
|
||||
REQUIRE(resolved != nullptr);
|
||||
CHECK(resolved->name == "New Process");
|
||||
}
|
||||
|
||||
// A child inheriting either former name resolves through the runtime walker.
|
||||
Preset &child = add_inmemory_preset(coll, "Child Process", "Original Process");
|
||||
REQUIRE(coll.get_preset_parent(child) != nullptr);
|
||||
CHECK(coll.get_preset_parent(child)->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset2 auto-matches removed Generic vendor profiles to the library", "[Preset][Rename]")
|
||||
{
|
||||
PresetBundle bundle;
|
||||
|
||||
// The OrcaFilamentLibrary replacement that removed empty "<vendor> Generic" profiles map to.
|
||||
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
||||
|
||||
// Plain lookups do NOT fuzzy-match a removed vendor profile.
|
||||
CHECK(bundle.filaments.find_preset("Voron Generic PLA") == nullptr);
|
||||
CHECK(bundle.filaments.find_preset2("Voron Generic PLA", /*auto_match=*/false) == nullptr);
|
||||
|
||||
// With auto_match, the removed "Voron Generic PLA" resolves to "Generic PLA @System".
|
||||
const Preset *matched = bundle.filaments.find_preset2("Voron Generic PLA", /*auto_match=*/true);
|
||||
REQUIRE(matched != nullptr);
|
||||
CHECK(matched->name == "Generic PLA @System");
|
||||
|
||||
// No library preset exists for an unrelated material => still no match.
|
||||
CHECK(bundle.filaments.find_preset2("BrandX Generic PETG", /*auto_match=*/true) == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
||||
{
|
||||
TempPresetDir temp_dir;
|
||||
RenameTestCollection coll;
|
||||
|
||||
// Current parent, renamed from "Old Process".
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// A user preset on disk that still inherits the OLD name.
|
||||
write_preset_with_inherits(coll.default_preset().config,
|
||||
temp_dir.path / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process");
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
const Preset *child = coll.find_preset("Child");
|
||||
REQUIRE(child != nullptr);
|
||||
// The dangling "Old Process" was rewritten to the resolved parent name at load time,
|
||||
// so the runtime walker (plain find_preset) can resolve the chain.
|
||||
CHECK(child->inherits() == "New Process");
|
||||
REQUIRE(coll.get_preset_parent(*child) != nullptr);
|
||||
CHECK(coll.get_preset_parent(*child)->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("Removed Generic parent is normalized into a loaded filament's inherits", "[Preset][Rename]")
|
||||
{
|
||||
TempPresetDir temp_dir;
|
||||
PresetBundle bundle;
|
||||
|
||||
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
||||
|
||||
// A user filament that still inherits a removed "<vendor> Generic PLA" profile.
|
||||
write_preset_with_inherits(bundle.filaments.default_preset().config,
|
||||
temp_dir.path / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA");
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
bundle.filaments.load_presets(temp_dir.path.string(), PRESET_FILAMENT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
const Preset *child = bundle.filaments.find_preset("MyPLA");
|
||||
REQUIRE(child != nullptr);
|
||||
CHECK(child->inherits() == "Generic PLA @System");
|
||||
REQUIRE(bundle.filaments.get_preset_parent(*child) != nullptr);
|
||||
CHECK(bundle.filaments.get_preset_parent(*child)->name == "Generic PLA @System");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user