mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-30 04:11:00 +00:00
libslic3r: resolve a vendor's cached presets together
Installing one entry is a config copy, the entry's diff applied over it, normalization and an invalid-key scan. For the largest vendor that is around 2000 filaments at about 115 us each, and all of it reads state that does not change while the collection loads. load_vendor_preset splits into resolve_vendor_preset, which flattens an entry and touches nothing shared, and commit_vendor_preset, which installs it. A cache load installs the entries others inherit from first, since what those register is what the rest resolve against, then resolves the rest together and commits them one at a time. The JSON parse calls the two back to back as before. On a 16-core desktop with 4263 system presets installed, preset loading goes from 644-652 ms to 370-376 ms, and a bundle loaded either way comes out identical, preset for preset and option for option.
This commit is contained in:
+197
-129
@@ -20,6 +20,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <thread>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@@ -6619,33 +6620,24 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": finished");
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orca: load one source-form preset entry — parsed from its JSON subfile just
|
PresetBundle::PresetInstall PresetBundle::resolve_vendor_preset(
|
||||||
// now, or deserialized from the vendor's cache; the code is shared so a
|
|
||||||
// cache-loaded bundle cannot come out different from a JSON-loaded one.
|
|
||||||
// Resolves `inherits` against the presets loaded before this one
|
|
||||||
// (config_maps) or against base_bundle's filament library, layers each
|
|
||||||
// `include` (include_maps) under the preset's own keys, flattens, validates
|
|
||||||
// and registers the preset. Returns the reason loading failed, empty on
|
|
||||||
// success.
|
|
||||||
std::string PresetBundle::load_vendor_preset(
|
|
||||||
const CachedPreset& entry,
|
const CachedPreset& entry,
|
||||||
const std::string& path, const std::string& vendor_name,
|
const std::string& path, const std::string& vendor_name,
|
||||||
const PresetBundle* base_bundle,
|
const PresetBundle* base_bundle,
|
||||||
LoadConfigBundleAttributes flags,
|
const std::map<std::string, DynamicPrintConfig>& config_maps,
|
||||||
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
|
const std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
const std::map<std::string, std::string>& filament_id_maps,
|
||||||
std::map<std::string, std::string>& filament_id_maps,
|
const PresetCollection& presets_collection,
|
||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
const std::set<std::string>* retain_includes) const
|
||||||
const std::set<std::string>* retain_configs, const std::set<std::string>* retain_includes)
|
|
||||||
{
|
{
|
||||||
const VendorProfile* current_vendor_profile = &this->vendors.at(vendor_name);
|
const VendorProfile& current_vendor_profile = this->vendors.at(vendor_name);
|
||||||
const std::string subfile = path + "/" + vendor_name + "/" + entry.sub_path;
|
const std::string subfile = path + "/" + vendor_name + "/" + entry.sub_path;
|
||||||
const std::string& preset_name = entry.name;
|
const std::string& preset_name = entry.name;
|
||||||
std::string alias_name, filament_id = entry.filament_id;
|
|
||||||
std::vector<std::string> renamed_from = entry.renamed_from;
|
|
||||||
DynamicPrintConfig config;
|
|
||||||
const DynamicPrintConfig* default_config = nullptr;
|
const DynamicPrintConfig* default_config = nullptr;
|
||||||
std::string reason;
|
|
||||||
|
PresetInstall out;
|
||||||
|
out.filament_id = entry.filament_id;
|
||||||
|
out.renamed_from = entry.renamed_from;
|
||||||
|
|
||||||
//check whether it inherits other preset or not
|
//check whether it inherits other preset or not
|
||||||
if (! entry.inherits.empty()) {
|
if (! entry.inherits.empty()) {
|
||||||
@@ -6658,115 +6650,99 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
default_config = &(base_it2->second);
|
default_config = &(base_it2->second);
|
||||||
}
|
}
|
||||||
if (default_config != nullptr) {
|
if (default_config != nullptr) {
|
||||||
if (filament_id.empty() && (presets_collection->type() == Preset::TYPE_FILAMENT)) {
|
if (out.filament_id.empty() && (presets_collection.type() == Preset::TYPE_FILAMENT)) {
|
||||||
auto filament_id_map_iter = filament_id_maps.find(entry.inherits);
|
auto filament_id_map_iter = filament_id_maps.find(entry.inherits);
|
||||||
if (filament_id_map_iter != filament_id_maps.end()) {
|
if (filament_id_map_iter != filament_id_maps.end()) {
|
||||||
filament_id = filament_id_map_iter->second;
|
out.filament_id = filament_id_map_iter->second;
|
||||||
}
|
}
|
||||||
if (filament_id.empty() && base_bundle != nullptr) {
|
if (out.filament_id.empty() && base_bundle != nullptr) {
|
||||||
auto base_filament_id_map_iter = base_bundle->m_filament_id_maps.find(entry.inherits);
|
auto base_filament_id_map_iter = base_bundle->m_filament_id_maps.find(entry.inherits);
|
||||||
if (base_filament_id_map_iter != base_bundle->m_filament_id_maps.end()) {
|
if (base_filament_id_map_iter != base_bundle->m_filament_id_maps.end()) {
|
||||||
filament_id = base_filament_id_map_iter->second;
|
out.filament_id = base_filament_id_map_iter->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
++m_errors;
|
out.errors.push_back(std::string(__FUNCTION__) + ": can not find inherits " + entry.inherits + " for " + preset_name);
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": can not find inherits " << entry.inherits << " for " << preset_name;
|
out.reason = "Can not find inherits: " + entry.inherits;
|
||||||
// throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name));
|
return out;
|
||||||
reason = "Can not find inherits: " + entry.inherits;
|
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
default_config = &presets_collection->default_preset_for(entry.config_src).config;
|
default_config = &presets_collection.default_preset_for(entry.config_src).config;
|
||||||
config = *default_config;
|
out.config = *default_config;
|
||||||
// Layer each included preset's own keys over the parent, in the order listed;
|
// Layer each included preset's own keys over the parent, in the order listed;
|
||||||
// this preset's own keys go on top.
|
// this preset's own keys go on top.
|
||||||
for (const std::string& name : entry.includes) {
|
for (const std::string& name : entry.includes) {
|
||||||
auto it = include_maps.find(name);
|
auto it = include_maps.find(name);
|
||||||
if (it == include_maps.end()) {
|
if (it == include_maps.end()) {
|
||||||
++m_errors;
|
out.errors.push_back(std::string(__FUNCTION__) + ": can not find include " + name + " for " + preset_name);
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": can not find include " << name << " for " << preset_name;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
config.apply(it->second);
|
out.config.apply(it->second);
|
||||||
}
|
}
|
||||||
config.apply(entry.config_src);
|
out.config.apply(entry.config_src);
|
||||||
// Record what a base states, its diff against the default, for the presets
|
// Record what a base states, its diff against the default, for the presets
|
||||||
// that include it. It is taken before extend_default_config_length pads every
|
// that include it. It is taken before extend_default_config_length pads every
|
||||||
// per-variant key to the base's variant count: the padded defaults would
|
// per-variant key to the base's variant count: the padded defaults would
|
||||||
// otherwise override the values each includer inherits.
|
// otherwise override the values each includer inherits.
|
||||||
if (entry.instantiation == "false" && (retain_includes == nullptr || retain_includes->count(preset_name) != 0)) {
|
if (entry.instantiation == "false" && (retain_includes == nullptr || retain_includes->count(preset_name) != 0)) {
|
||||||
DynamicPrintConfig included;
|
out.included.emplace();
|
||||||
included.apply_only(config, config.diff(presets_collection->default_preset_for(config).config));
|
out.included->apply_only(out.config, out.config.diff(presets_collection.default_preset_for(out.config).config));
|
||||||
include_maps.emplace(preset_name, std::move(included));
|
|
||||||
}
|
}
|
||||||
extend_default_config_length(config, true, *default_config);
|
extend_default_config_length(out.config, true, *default_config);
|
||||||
if (entry.instantiation == "false" && "Template" != vendor_name) {
|
if (entry.instantiation == "false" && "Template" != vendor_name) {
|
||||||
// Report configuration fields, which are misplaced into a wrong group.
|
// Report configuration fields, which are misplaced into a wrong group.
|
||||||
std::string incorrect_keys = Preset::remove_invalid_keys(config, *default_config);
|
std::string incorrect_keys = Preset::remove_invalid_keys(out.config, *default_config);
|
||||||
if (!incorrect_keys.empty()) {
|
if (!incorrect_keys.empty())
|
||||||
++m_errors;
|
out.errors.push_back(std::string(__FUNCTION__) + ": The config " + subfile + " contains incorrect keys: " +
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": The config " << subfile << " contains incorrect keys: " << incorrect_keys
|
incorrect_keys + ", which were removed");
|
||||||
<< ", which were removed";
|
out.config_only = true;
|
||||||
}
|
return out;
|
||||||
|
|
||||||
if (retain_configs == nullptr || retain_configs->count(preset_name) != 0)
|
|
||||||
config_maps.emplace(preset_name, std::move(config));
|
|
||||||
if ((presets_collection->type() == Preset::TYPE_FILAMENT) && (!filament_id.empty()))
|
|
||||||
filament_id_maps.emplace(preset_name, filament_id);
|
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
if (config.has("alias"))
|
if (out.config.has("alias"))
|
||||||
alias_name = (dynamic_cast<const ConfigOptionString *>(config.option("alias")))->value;
|
out.alias = (dynamic_cast<const ConfigOptionString *>(out.config.option("alias")))->value;
|
||||||
Preset::normalize(config);
|
Preset::normalize(out.config);
|
||||||
|
|
||||||
// Report configuration fields, which are misplaced into a wrong group.
|
// Report configuration fields, which are misplaced into a wrong group.
|
||||||
std::string incorrect_keys = Preset::remove_invalid_keys(config, *default_config);
|
std::string incorrect_keys = Preset::remove_invalid_keys(out.config, *default_config);
|
||||||
if (!incorrect_keys.empty()) {
|
if (!incorrect_keys.empty())
|
||||||
++m_errors;
|
out.errors.push_back(std::string(__FUNCTION__) + ": The config " + subfile + " contains incorrect keys: " +
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": The config " << subfile << " contains incorrect keys: " << incorrect_keys
|
incorrect_keys + ", which were removed");
|
||||||
<< ", which were removed";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presets_collection->type() == Preset::TYPE_PRINTER) {
|
if (presets_collection.type() == Preset::TYPE_PRINTER) {
|
||||||
// Filter out printer presets, which are not mentioned in the vendor profile.
|
// Filter out printer presets, which are not mentioned in the vendor profile.
|
||||||
// These presets are considered not installed.
|
// These presets are considered not installed.
|
||||||
auto printer_model = config.opt_string("printer_model");
|
auto printer_model = out.config.opt_string("printer_model");
|
||||||
if (printer_model.empty()) {
|
if (printer_model.empty()) {
|
||||||
++m_errors;
|
out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
preset_name + "\" defines no printer model, it will be ignored.");
|
||||||
preset_name << "\" defines no printer model, it will be ignored.";
|
out.reason = std::string("can not find printer_model");
|
||||||
reason = std::string("can not find printer_model");
|
return out;
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
auto printer_variant = config.opt_string("printer_variant");
|
auto printer_variant = out.config.opt_string("printer_variant");
|
||||||
if (printer_variant.empty()) {
|
if (printer_variant.empty()) {
|
||||||
++m_errors;
|
out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
preset_name + "\" defines no printer variant, it will be ignored.");
|
||||||
preset_name << "\" defines no printer variant, it will be ignored.";
|
out.reason = std::string("can not find printer_variant");
|
||||||
reason = std::string("can not find printer_variant");
|
return out;
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
auto it_model = std::find_if(current_vendor_profile->models.cbegin(), current_vendor_profile->models.cend(),
|
auto it_model = std::find_if(current_vendor_profile.models.cbegin(), current_vendor_profile.models.cend(),
|
||||||
[&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; }
|
[&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; }
|
||||||
);
|
);
|
||||||
if (it_model == current_vendor_profile->models.end()) {
|
if (it_model == current_vendor_profile.models.end()) {
|
||||||
++m_errors;
|
out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
preset_name + "\" defines invalid printer model \"" + printer_model + "\", it will be ignored.");
|
||||||
preset_name << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored.";
|
out.reason = std::string("can not find printer model in vendor profile");
|
||||||
reason = std::string("can not find printer model in vendor profile");
|
return out;
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
auto it_variant = it_model->variant(printer_variant);
|
auto it_variant = it_model->variant(printer_variant);
|
||||||
if (it_variant == nullptr) {
|
if (it_variant == nullptr) {
|
||||||
++m_errors;
|
out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
preset_name + "\" defines invalid printer variant \"" + printer_variant + "\", it will be ignored.");
|
||||||
preset_name << "\" defines invalid printer variant \"" << printer_variant << "\", it will be ignored.";
|
out.reason = std::string("can not find printer_variant in vendor profile");
|
||||||
reason = std::string("can not find printer_variant in vendor profile");
|
return out;
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
// An instantiation printer profile's nozzle_diameter must match the numeric (diameter)
|
// An instantiation printer profile's nozzle_diameter must match the numeric (diameter)
|
||||||
// prefix of its printer_variant: "0.4" -> {0.4}, "0.8HF" -> {0.8} (a trailing
|
// prefix of its printer_variant: "0.4" -> {0.4}, "0.8HF" -> {0.8} (a trailing
|
||||||
@@ -6777,7 +6753,7 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
// validated, not variant uniqueness. Validation-only so the app keeps loading existing
|
// validated, not variant uniqueness. Validation-only so the app keeps loading existing
|
||||||
// profiles unchanged.
|
// profiles unchanged.
|
||||||
if (validation_mode && entry.instantiation == "true") {
|
if (validation_mode && entry.instantiation == "true") {
|
||||||
const auto *nd = config.option<ConfigOptionFloats>("nozzle_diameter");
|
const auto *nd = out.config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||||
std::set<double> nozzles, variant_nozzles;
|
std::set<double> nozzles, variant_nozzles;
|
||||||
if (nd != nullptr)
|
if (nd != nullptr)
|
||||||
nozzles.insert(nd->values.begin(), nd->values.end());
|
nozzles.insert(nd->values.begin(), nd->values.end());
|
||||||
@@ -6792,33 +6768,77 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
variant_nozzles.insert(d);
|
variant_nozzles.insert(d);
|
||||||
}
|
}
|
||||||
if (!variant_ok || variant_nozzles != nozzles) {
|
if (!variant_ok || variant_nozzles != nozzles) {
|
||||||
++m_errors;
|
out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
preset_name + "\" has printer_variant \"" + printer_variant +
|
||||||
preset_name << "\" has printer_variant \"" << printer_variant <<
|
"\" that does not match its nozzle_diameter \"" + (nd ? nd->serialize() : std::string()) + "\". "
|
||||||
"\" that does not match its nozzle_diameter \"" << (nd ? nd->serialize() : std::string()) << "\". "
|
|
||||||
"printer_variant must begin with the nozzle diameter, optionally followed by a non-numeric suffix "
|
"printer_variant must begin with the nozzle diameter, optionally followed by a non-numeric suffix "
|
||||||
"(e.g. \"0.4\", \"0.8HF\"); for multi-nozzle printers, join the per-nozzle diameters with \"+\" in "
|
"(e.g. \"0.4\", \"0.8HF\"); for multi-nozzle printers, join the per-nozzle diameters with \"+\" in "
|
||||||
"nozzle order (e.g. \"0.4+0.6\").";
|
"nozzle order (e.g. \"0.4+0.6\").");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derive the profile logical name aka alias from the preset name if the alias was not stated explicitely.
|
||||||
|
if (out.alias.empty()) {
|
||||||
|
size_t end_pos = preset_name.find_first_of("@");
|
||||||
|
if (end_pos != std::string::npos) {
|
||||||
|
out.alias = preset_name.substr(0, end_pos);
|
||||||
|
if (out.renamed_from.empty())
|
||||||
|
// Add the preset name with the '@' character removed into the "renamed_from" list.
|
||||||
|
out.renamed_from.emplace_back(out.alias + preset_name.substr(end_pos + 1));
|
||||||
|
boost::trim_right(out.alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.file_path = (boost::filesystem::path(data_dir()) / PRESET_SYSTEM_DIR / vendor_name / entry.sub_path).make_preferred().string();
|
||||||
|
if (validation_mode)
|
||||||
|
out.file_path = (boost::filesystem::path(data_dir()) / vendor_name / entry.sub_path).make_preferred().string();
|
||||||
|
if (m_preserve_vendor_source_paths)
|
||||||
|
out.file_path = (boost::filesystem::path(path) / vendor_name / entry.sub_path).make_preferred().string();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PresetBundle::commit_vendor_preset(
|
||||||
|
const CachedPreset& entry, PresetInstall&& resolved,
|
||||||
|
const std::string& path, const std::string& vendor_name,
|
||||||
|
LoadConfigBundleAttributes flags,
|
||||||
|
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
|
||||||
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
const std::set<std::string>* retain_configs)
|
||||||
|
{
|
||||||
|
const VendorProfile* current_vendor_profile = &this->vendors.at(vendor_name);
|
||||||
|
const std::string& preset_name = entry.name;
|
||||||
|
const std::string subfile = path + "/" + vendor_name + "/" + entry.sub_path;
|
||||||
|
|
||||||
|
for (const std::string& error : resolved.errors) {
|
||||||
|
++m_errors;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << error;
|
||||||
|
}
|
||||||
|
if (resolved.included)
|
||||||
|
include_maps.emplace(preset_name, std::move(*resolved.included));
|
||||||
|
if (! resolved.reason.empty())
|
||||||
|
return resolved.reason;
|
||||||
|
|
||||||
|
if (resolved.config_only) {
|
||||||
|
if (retain_configs == nullptr || retain_configs->count(preset_name) != 0)
|
||||||
|
config_maps.emplace(preset_name, std::move(resolved.config));
|
||||||
|
if ((presets_collection->type() == Preset::TYPE_FILAMENT) && (!resolved.filament_id.empty()))
|
||||||
|
filament_id_maps.emplace(preset_name, resolved.filament_id);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
const Preset *preset_existing = presets_collection->find_preset(preset_name, false);
|
const Preset *preset_existing = presets_collection->find_preset(preset_name, false);
|
||||||
if (preset_existing != nullptr) {
|
if (preset_existing != nullptr) {
|
||||||
++m_errors;
|
++m_errors;
|
||||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||||
preset_name << "\" has already been loaded from another Config Bundle.";
|
preset_name << "\" has already been loaded from another Config Bundle.";
|
||||||
reason = std::string("duplicated defines");
|
return std::string("duplicated defines");
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto file_path = (boost::filesystem::path(data_dir()) / PRESET_SYSTEM_DIR / vendor_name / entry.sub_path).make_preferred();
|
|
||||||
if (validation_mode)
|
|
||||||
file_path = (boost::filesystem::path(data_dir()) / vendor_name / entry.sub_path).make_preferred();
|
|
||||||
if (m_preserve_vendor_source_paths)
|
|
||||||
file_path = (boost::filesystem::path(path) / vendor_name / entry.sub_path).make_preferred();
|
|
||||||
|
|
||||||
// Load the preset into the list of presets, save it to disk.
|
// Load the preset into the list of presets, save it to disk.
|
||||||
Preset &loaded = presets_collection->load_preset(file_path.string(), preset_name, std::move(config), false);
|
Preset &loaded = presets_collection->load_preset(resolved.file_path, preset_name, std::move(resolved.config), false);
|
||||||
if (flags.has(LoadConfigBundleAttribute::LoadSystem)) {
|
if (flags.has(LoadConfigBundleAttribute::LoadSystem)) {
|
||||||
loaded.is_system = true;
|
loaded.is_system = true;
|
||||||
loaded.vendor = current_vendor_profile;
|
loaded.vendor = current_vendor_profile;
|
||||||
@@ -6832,41 +6852,29 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
if (loaded.setting_id.empty() && entry.instantiation == "true")
|
if (loaded.setting_id.empty() && entry.instantiation == "true")
|
||||||
loaded.setting_id = generate_preset_setting_id(
|
loaded.setting_id = generate_preset_setting_id(
|
||||||
vendor_name, Preset::get_type_string(presets_collection->type()), preset_name);
|
vendor_name, Preset::get_type_string(presets_collection->type()), preset_name);
|
||||||
loaded.filament_id = filament_id;
|
loaded.filament_id = resolved.filament_id;
|
||||||
loaded.m_from_orca_filament_lib = is_from_lib;
|
loaded.m_from_orca_filament_lib = is_from_lib;
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << __LINE__ << ", " << loaded.name << " load filament_id: " << filament_id;
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << __LINE__ << ", " << loaded.name << " load filament_id: " << resolved.filament_id;
|
||||||
if (presets_collection->type() == Preset::TYPE_FILAMENT) {
|
if (presets_collection->type() == Preset::TYPE_FILAMENT) {
|
||||||
if (filament_id.empty() && "Template" != vendor_name) {
|
if (resolved.filament_id.empty() && "Template" != vendor_name) {
|
||||||
++m_errors;
|
++m_errors;
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": can not find filament_id for " << preset_name;
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": can not find filament_id for " << preset_name;
|
||||||
//throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name));
|
//throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name));
|
||||||
reason = "Can not find filament_id for " + preset_name;
|
return "Can not find filament_id for " + preset_name;
|
||||||
return reason;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
filament_id_maps.emplace(preset_name, filament_id);
|
filament_id_maps.emplace(preset_name, resolved.filament_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive the profile logical name aka alias from the preset name if the alias was not stated explicitely.
|
if (resolved.alias.empty())
|
||||||
if (alias_name.empty()) {
|
|
||||||
size_t end_pos = preset_name.find_first_of("@");
|
|
||||||
if (end_pos != std::string::npos) {
|
|
||||||
alias_name = preset_name.substr(0, end_pos);
|
|
||||||
if (renamed_from.empty())
|
|
||||||
// Add the preset name with the '@' character removed into the "renamed_from" list.
|
|
||||||
renamed_from.emplace_back(alias_name + preset_name.substr(end_pos + 1));
|
|
||||||
boost::trim_right(alias_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alias_name.empty())
|
|
||||||
loaded.alias = preset_name;
|
loaded.alias = preset_name;
|
||||||
else {
|
else {
|
||||||
loaded.alias = std::move(alias_name);
|
loaded.alias = std::move(resolved.alias);
|
||||||
filaments.set_printer_hold_alias(loaded.alias, loaded);
|
filaments.set_printer_hold_alias(loaded.alias, loaded);
|
||||||
}
|
}
|
||||||
loaded.renamed_from = std::move(renamed_from);
|
loaded.renamed_from = std::move(resolved.renamed_from);
|
||||||
if (! substitution_context.empty())
|
if (! substitution_context.empty())
|
||||||
substitutions.push_back({
|
substitutions.push_back({
|
||||||
preset_name, presets_collection->type(), PresetConfigSubstitutions::Source::ConfigBundle,
|
preset_name, presets_collection->type(), PresetConfigSubstitutions::Source::ConfigBundle,
|
||||||
@@ -6876,7 +6884,28 @@ std::string PresetBundle::load_vendor_preset(
|
|||||||
++count;
|
++count;
|
||||||
//BBS: add config related logs
|
//BBS: add config related logs
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", got preset %1%, from %2%")%loaded.name %subfile;
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", got preset %1%, from %2%")%loaded.name %subfile;
|
||||||
return reason;
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orca: load one source-form preset entry — parsed from its JSON subfile just
|
||||||
|
// now, or deserialized from the vendor's cache; the code is shared so a
|
||||||
|
// cache-loaded bundle cannot come out different from a JSON-loaded one.
|
||||||
|
std::string PresetBundle::load_vendor_preset(
|
||||||
|
const CachedPreset& entry,
|
||||||
|
const std::string& path, const std::string& vendor_name,
|
||||||
|
const PresetBundle* base_bundle,
|
||||||
|
LoadConfigBundleAttributes flags,
|
||||||
|
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
|
||||||
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
const std::set<std::string>* retain_configs, const std::set<std::string>* retain_includes)
|
||||||
|
{
|
||||||
|
PresetInstall resolved = this->resolve_vendor_preset(entry, path, vendor_name, base_bundle,
|
||||||
|
config_maps, include_maps, filament_id_maps, *presets_collection, retain_includes);
|
||||||
|
return this->commit_vendor_preset(entry, std::move(resolved), path, vendor_name, flags,
|
||||||
|
substitution_context, substitutions, config_maps, include_maps, filament_id_maps, presets_collection,
|
||||||
|
count, is_from_lib, retain_configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//BBS: Load a config bundle file from json
|
//BBS: Load a config bundle file from json
|
||||||
@@ -8043,10 +8072,12 @@ bool PresetBundle::load_vendor_cache(const std::string& cache_path, const std::s
|
|||||||
// own below, so m_errors comes out as a JSON parse would leave it.
|
// own below, so m_errors comes out as a JSON parse would leave it.
|
||||||
m_errors += int(data.parse_errors);
|
m_errors += int(data.parse_errors);
|
||||||
|
|
||||||
// Install the entries exactly as load_vendor_configs_from_json installs
|
// Install the entries through the same code load_vendor_configs_from_json
|
||||||
// them straight after parsing — same code, same order. The substitution
|
// installs them with straight after parsing. The entries others inherit
|
||||||
// context stays empty (the entries were substituted when they were
|
// from or include go in first here rather than in listing order, which the
|
||||||
// parsed), so no substitutions are reported, as before.
|
// collection being sorted afterwards makes unobservable. The substitution context
|
||||||
|
// stays empty (the entries were substituted when they were parsed), so no
|
||||||
|
// substitutions are reported, as before.
|
||||||
ConfigSubstitutionContext substitution_context { ForwardCompatibilitySubstitutionRule::EnableSilent };
|
ConfigSubstitutionContext substitution_context { ForwardCompatibilitySubstitutionRule::EnableSilent };
|
||||||
PresetsConfigSubstitutions substitutions;
|
PresetsConfigSubstitutions substitutions;
|
||||||
std::map<std::string, DynamicPrintConfig> configs, include_maps;
|
std::map<std::string, DynamicPrintConfig> configs, include_maps;
|
||||||
@@ -8068,13 +8099,50 @@ bool PresetBundle::load_vendor_cache(const std::string& cache_path, const std::s
|
|||||||
included.insert(entry.includes.begin(), entry.includes.end());
|
included.insert(entry.includes.begin(), entry.includes.end());
|
||||||
}
|
}
|
||||||
const std::set<std::string>* retain_configs = is_from_lib ? nullptr : &inherited;
|
const std::set<std::string>* retain_configs = is_from_lib ? nullptr : &inherited;
|
||||||
for (const CachedPreset& entry : entries) {
|
|
||||||
const std::string reason = load_vendor_preset(entry, path, vendor_name,
|
auto commit = [&](const CachedPreset& entry, PresetInstall&& resolved) {
|
||||||
base_bundle, LoadConfigBundleAttribute::LoadSystem, substitution_context, substitutions,
|
const std::string reason = commit_vendor_preset(entry, std::move(resolved), path, vendor_name,
|
||||||
configs, include_maps, filament_id_maps, presets, count, is_from_lib, retain_configs, &included);
|
LoadConfigBundleAttribute::LoadSystem, substitution_context, substitutions,
|
||||||
|
configs, include_maps, filament_id_maps, presets, count, is_from_lib, retain_configs);
|
||||||
if (! reason.empty())
|
if (! reason.empty())
|
||||||
throw std::runtime_error("entry " + entry.name + " failed to install: " + reason);
|
throw std::runtime_error("entry " + entry.name + " failed to install: " + reason);
|
||||||
|
};
|
||||||
|
auto resolve = [&](const CachedPreset& entry) {
|
||||||
|
return resolve_vendor_preset(entry, path, vendor_name, base_bundle, configs, include_maps, filament_id_maps,
|
||||||
|
*presets, &included);
|
||||||
|
};
|
||||||
|
|
||||||
|
// An entry others inherit from or include is installed before them, in
|
||||||
|
// the order the vendor lists them, because what it registers in `configs`
|
||||||
|
// or `include_maps` is what they resolve against. So is an entry that
|
||||||
|
// includes one listed after it, which it must find missing. The rest
|
||||||
|
// depend on nothing else, so they resolve at once. Two cores or fewer
|
||||||
|
// stay one at a time.
|
||||||
|
const bool resolve_together = std::thread::hardware_concurrency() > 2;
|
||||||
|
std::vector<size_t> leaves;
|
||||||
|
leaves.reserve(entries.size());
|
||||||
|
for (size_t i = 0; i < entries.size(); ++ i) {
|
||||||
|
const CachedPreset& entry = entries[i];
|
||||||
|
const bool includes_installed = std::all_of(entry.includes.begin(), entry.includes.end(),
|
||||||
|
[&](const std::string& name) { return include_maps.count(name) != 0; });
|
||||||
|
if (resolve_together && inherited.count(entry.name) == 0 && included.count(entry.name) == 0 && includes_installed)
|
||||||
|
leaves.push_back(i);
|
||||||
|
else
|
||||||
|
commit(entry, resolve(entry));
|
||||||
}
|
}
|
||||||
|
if (leaves.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<PresetInstall> resolved(leaves.size());
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, leaves.size()),
|
||||||
|
[&](const tbb::blocked_range<size_t>& range) {
|
||||||
|
for (size_t k = range.begin(); k < range.end(); ++ k)
|
||||||
|
resolved[k] = resolve(entries[leaves[k]]);
|
||||||
|
});
|
||||||
|
// Installed in the order the vendor lists them, so a duplicate name
|
||||||
|
// or a rejected entry is reported as it would be one at a time.
|
||||||
|
for (size_t k = 0; k < leaves.size(); ++ k)
|
||||||
|
commit(entries[leaves[k]], std::move(resolved[k]));
|
||||||
};
|
};
|
||||||
install_entries(data.process_entries, &this->prints, false);
|
install_entries(data.process_entries, &this->prints, false);
|
||||||
const bool is_orca_lib = vendor_name == ORCA_FILAMENT_LIBRARY;
|
const bool is_orca_lib = vendor_name == ORCA_FILAMENT_LIBRARY;
|
||||||
|
|||||||
@@ -653,6 +653,51 @@ private:
|
|||||||
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
const std::set<std::string>* retain_configs = nullptr, const std::set<std::string>* retain_includes = nullptr);
|
const std::set<std::string>* retain_configs = nullptr, const std::set<std::string>* retain_includes = nullptr);
|
||||||
|
|
||||||
|
// One entry flattened against the preset it inherits, before anything this
|
||||||
|
// bundle shares has been touched.
|
||||||
|
struct PresetInstall
|
||||||
|
{
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
std::string file_path;
|
||||||
|
// Empty when the preset is its own alias.
|
||||||
|
std::string alias;
|
||||||
|
std::string filament_id;
|
||||||
|
std::vector<std::string> renamed_from;
|
||||||
|
// Reported by commit, so resolving entries together leaves the log and
|
||||||
|
// the error count as one entry at a time produces them.
|
||||||
|
std::vector<std::string> errors;
|
||||||
|
// What a base states for the presets that include it, when it is retained.
|
||||||
|
std::optional<DynamicPrintConfig> included;
|
||||||
|
// Inherited from and nothing else, so it contributes a config and no preset.
|
||||||
|
bool config_only { false };
|
||||||
|
// Non-empty when the entry is rejected, and says why.
|
||||||
|
std::string reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Flatten one entry against config_maps (this bundle's presets) or
|
||||||
|
// base_bundle's filament library, with the bases it includes from
|
||||||
|
// include_maps. It reads only, so entries whose parents are already
|
||||||
|
// installed resolve independently of each other.
|
||||||
|
PresetInstall resolve_vendor_preset(const CachedPreset& entry,
|
||||||
|
const std::string& path, const std::string& vendor_name,
|
||||||
|
const PresetBundle* base_bundle,
|
||||||
|
const std::map<std::string, DynamicPrintConfig>& config_maps,
|
||||||
|
const std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
|
const std::map<std::string, std::string>& filament_id_maps,
|
||||||
|
const PresetCollection& presets_collection,
|
||||||
|
const std::set<std::string>* retain_includes = nullptr) const;
|
||||||
|
|
||||||
|
// Install a resolved entry. The collections, the inheritance maps and the
|
||||||
|
// error count are touched here and only here, one entry at a time.
|
||||||
|
std::string commit_vendor_preset(const CachedPreset& entry, PresetInstall&& resolved,
|
||||||
|
const std::string& path, const std::string& vendor_name,
|
||||||
|
LoadConfigBundleAttributes flags,
|
||||||
|
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
|
||||||
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
|
const std::set<std::string>* retain_configs = nullptr);
|
||||||
|
|
||||||
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
||||||
void clear_printer_hold_aliases();
|
void clear_printer_hold_aliases();
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,35 @@ void write_lib_tree(const fs::path& dir, const std::string& version, const std::
|
|||||||
<< R"("filament_id":"GFL99","filament_cost":")" << cost << R"("})";
|
<< R"("filament_id":"GFL99","filament_cost":")" << cost << R"("})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A vendor wide enough for a cache load to resolve its entries together, with
|
||||||
|
// two levels of inheritance the load has to work through in order and `leaves`
|
||||||
|
// presets that depend on nothing but those.
|
||||||
|
void write_wide_vendor_tree(const fs::path& dir, const std::string& vendor, const std::string& version, int leaves)
|
||||||
|
{
|
||||||
|
fs::create_directories(dir / vendor / "filament");
|
||||||
|
std::ostringstream filament_list;
|
||||||
|
filament_list << R"({"name":")" << vendor << R"( Base PLA","sub_path":"filament/base.json"},)"
|
||||||
|
<< R"({"name":")" << vendor << R"( Mid PLA","sub_path":"filament/mid.json"})";
|
||||||
|
for (int i = 0; i < leaves; ++ i)
|
||||||
|
filament_list << R"(,{"name":")" << vendor << " PLA " << i << R"( @0.4","sub_path":"filament/leaf)"
|
||||||
|
<< i << R"(.json"})";
|
||||||
|
std::ofstream((dir / (vendor + ".json")).string())
|
||||||
|
<< R"({"version":")" << version << R"(","name":")" << vendor << R"(","filament_list":[)"
|
||||||
|
<< filament_list.str() << "]}";
|
||||||
|
std::ofstream((dir / vendor / "filament" / "base.json").string())
|
||||||
|
<< R"({"type":"filament","name":")" << vendor
|
||||||
|
<< R"( Base PLA","from":"system","instantiation":"false","filament_id":"GFA_base","filament_cost":"42"})";
|
||||||
|
std::ofstream((dir / vendor / "filament" / "mid.json").string())
|
||||||
|
<< R"({"type":"filament","name":")" << vendor
|
||||||
|
<< R"( Mid PLA","from":"system","instantiation":"false","inherits":")" << vendor
|
||||||
|
<< R"( Base PLA","filament_flow_ratio":"0.95"})";
|
||||||
|
for (int i = 0; i < leaves; ++ i)
|
||||||
|
std::ofstream((dir / vendor / "filament" / ("leaf" + std::to_string(i) + ".json")).string())
|
||||||
|
<< R"({"type":"filament","name":")" << vendor << " PLA " << i
|
||||||
|
<< R"( @0.4","from":"system","instantiation":"true","inherits":")" << vendor
|
||||||
|
<< R"( Mid PLA","nozzle_temperature":")" << (200 + i % 40) << R"("})";
|
||||||
|
}
|
||||||
|
|
||||||
// A vendor whose one filament inherits the library's base and states nothing of
|
// A vendor whose one filament inherits the library's base and states nothing of
|
||||||
// its own — everything it shows comes from the library it is resolved against.
|
// its own — everything it shows comes from the library it is resolved against.
|
||||||
void write_vendor_with_lib_filament(const fs::path& dir, const std::string& vendor, const std::string& version)
|
void write_vendor_with_lib_filament(const fs::path& dir, const std::string& vendor, const std::string& version)
|
||||||
@@ -624,6 +653,86 @@ TEST_CASE("a cache-loaded vendor is indistinguishable from a JSON-loaded one", "
|
|||||||
CHECK(pr->config.opt_string("machine_start_gcode") == "G28 ; template"); // through the include
|
CHECK(pr->config.opt_string("machine_start_gcode") == "G28 ; template"); // through the include
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("a wide vendor loads from its cache exactly as it loads from JSON", "[VendorCache]")
|
||||||
|
{
|
||||||
|
TempDir tmp;
|
||||||
|
const fs::path rsrc = tmp.path / "resources" / "profiles";
|
||||||
|
const fs::path user = tmp.path / "data" / PRESET_SYSTEM_DIR;
|
||||||
|
fs::create_directories(rsrc);
|
||||||
|
fs::create_directories(user);
|
||||||
|
// Enough presets that the cache load resolves them across threads while the
|
||||||
|
// JSON parse below keeps installing them one at a time.
|
||||||
|
constexpr int leaves = 400;
|
||||||
|
write_wide_vendor_tree(user, "Acme", "1.0.0", leaves);
|
||||||
|
|
||||||
|
ScopedDirs dirs(tmp.path / "data", tmp.path / "resources");
|
||||||
|
|
||||||
|
PresetBundle from_json;
|
||||||
|
from_json.set_generate_vendor_caches(true);
|
||||||
|
from_json.load_vendor_configs_from_json(user.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
REQUIRE(fs::exists(user / "Acme.opc"));
|
||||||
|
|
||||||
|
fs::remove_all(user / "Acme");
|
||||||
|
PresetBundle from_cache;
|
||||||
|
from_cache.load_vendor_configs_from_json(user.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
|
||||||
|
auto a = presets_for(from_json.filaments, "Acme");
|
||||||
|
auto b = presets_for(from_cache.filaments, "Acme");
|
||||||
|
REQUIRE(a.size() == size_t(leaves));
|
||||||
|
REQUIRE(b.size() == a.size());
|
||||||
|
for (size_t i = 0; i < a.size(); ++ i) {
|
||||||
|
CHECK(a[i]->name == b[i]->name);
|
||||||
|
CHECK(preset_deep_equal(*a[i], *b[i]));
|
||||||
|
}
|
||||||
|
CHECK(from_cache.error_count() == from_json.error_count());
|
||||||
|
// The two-level chain resolved, so the leaf has the middle profile's flow ratio
|
||||||
|
// and the base profile's filament id, neither of which it states.
|
||||||
|
const Preset* leaf = from_cache.filaments.find_preset("Acme PLA 7 @0.4", false);
|
||||||
|
REQUIRE(leaf != nullptr);
|
||||||
|
CHECK(leaf->filament_id == "GFA_base");
|
||||||
|
const auto* flow = leaf->config.option<ConfigOptionFloats>("filament_flow_ratio");
|
||||||
|
REQUIRE(flow != nullptr);
|
||||||
|
CHECK_THAT(flow->values.front(), WithinAbs(0.95, 1e-9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("repeated cache loads of one vendor produce the same presets", "[VendorCache]")
|
||||||
|
{
|
||||||
|
TempDir tmp;
|
||||||
|
const fs::path rsrc = tmp.path / "resources" / "profiles";
|
||||||
|
const fs::path user = tmp.path / "data" / PRESET_SYSTEM_DIR;
|
||||||
|
fs::create_directories(rsrc);
|
||||||
|
fs::create_directories(user);
|
||||||
|
write_wide_vendor_tree(user, "Acme", "1.0.0", 400);
|
||||||
|
|
||||||
|
ScopedDirs dirs(tmp.path / "data", tmp.path / "resources");
|
||||||
|
|
||||||
|
PresetBundle seed;
|
||||||
|
seed.set_generate_vendor_caches(true);
|
||||||
|
seed.load_vendor_configs_from_json(user.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
REQUIRE(fs::exists(user / "Acme.opc"));
|
||||||
|
fs::remove_all(user / "Acme");
|
||||||
|
|
||||||
|
std::vector<PresetBundle> loads(3);
|
||||||
|
for (PresetBundle& bundle : loads)
|
||||||
|
bundle.load_vendor_configs_from_json(user.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
|
||||||
|
auto first = presets_for(loads[0].filaments, "Acme");
|
||||||
|
REQUIRE(!first.empty());
|
||||||
|
for (size_t run = 1; run < loads.size(); ++ run) {
|
||||||
|
auto again = presets_for(loads[run].filaments, "Acme");
|
||||||
|
REQUIRE(again.size() == first.size());
|
||||||
|
for (size_t i = 0; i < first.size(); ++ i) {
|
||||||
|
CHECK(first[i]->name == again[i]->name);
|
||||||
|
CHECK(preset_deep_equal(*first[i], *again[i]));
|
||||||
|
}
|
||||||
|
CHECK(loads[run].error_count() == loads[0].error_count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("a cache-served vendor reports the errors its parse counted", "[VendorCache]")
|
TEST_CASE("a cache-served vendor reports the errors its parse counted", "[VendorCache]")
|
||||||
{
|
{
|
||||||
TempDir tmp;
|
TempDir tmp;
|
||||||
@@ -1691,6 +1800,29 @@ TEST_CASE("an include listed after the preset that names it is an error, and the
|
|||||||
CHECK(silk->config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->values == std::vector<double>{12.});
|
CHECK(silk->config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->values == std::vector<double>{12.});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("an include listed after the preset that names it is missing from the cache load too", "[VendorCache]")
|
||||||
|
{
|
||||||
|
InstallDirs dirs;
|
||||||
|
write_full_vendor_tree(dirs.system, "Acme", "1.0.0", /*templates_last=*/true);
|
||||||
|
PresetBundle from_json;
|
||||||
|
from_json.set_generate_vendor_caches(true);
|
||||||
|
from_json.load_vendor_configs_from_json(dirs.system.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
REQUIRE(fs::exists(dirs.system / "Acme.opc"));
|
||||||
|
|
||||||
|
fs::remove_all(dirs.system / "Acme");
|
||||||
|
PresetBundle from_cache;
|
||||||
|
from_cache.load_vendor_configs_from_json(dirs.system.string(), "Acme", PresetBundle::LoadSystem,
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
CHECK(from_cache.error_count() == 2);
|
||||||
|
const Preset* pr = from_cache.printers.find_preset("Acme 0.4 nozzle", false);
|
||||||
|
REQUIRE(pr != nullptr);
|
||||||
|
CHECK(pr->config.opt_string("machine_start_gcode") != "G28 ; template");
|
||||||
|
const Preset* silk = from_cache.filaments.find_preset("Acme Silk PLA @0.4", false);
|
||||||
|
REQUIRE(silk != nullptr);
|
||||||
|
CHECK(silk->config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->values == std::vector<double>{12.});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("a G-code template that states no instantiation is included, not loaded as a preset", "[VendorCache]")
|
TEST_CASE("a G-code template that states no instantiation is included, not loaded as a preset", "[VendorCache]")
|
||||||
{
|
{
|
||||||
InstallDirs dirs;
|
InstallDirs dirs;
|
||||||
|
|||||||
Reference in New Issue
Block a user