Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/enhance profile validator #4278

Merged
merged 4 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion .github/workflows/build_orca.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,16 @@ jobs:
./BuildLinux.sh -isr
mv -n ./build/OrcaSlicer_Linux_V${{ env.ver_pure }}.AppImage ./build/OrcaSlicer_Linux_${{ env.ver }}.AppImage
chmod +x ./build/OrcaSlicer_Linux_${{ env.ver }}.AppImage


- name: Build orca_custom_preset_tests
if: github.ref == 'refs/heads/main' && inputs.os == 'ubuntu-20.04'
working-directory: ${{ github.workspace }}/build/src
shell: bash
run: |
OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -g 1
cd ${{ github.workspace }}/resources/profiles
zip -r orca_custom_preset_tests.zip user/

- name: Upload artifacts Ubuntu
if: inputs.os == 'ubuntu-20.04'
uses: actions/upload-artifact@v3
Expand All @@ -262,3 +271,14 @@ jobs:
asset_name: OrcaSlicer_Linux_${{ env.ver }}.AppImage
asset_content_type: application/octet-stream
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted

- name: Deploy orca_custom_preset_tests
if: github.ref == 'refs/heads/main' && inputs.os == 'ubuntu-20.04'
uses: WebFreak001/[email protected]
with:
upload_url: https://uploads.github.com/repos/SoftFever/OrcaSlicer/releases/137995723/assets{?name,label}
release_id: 137995723
asset_path: ${{ github.workspace }}/resources/profiles/orca_custom_preset_tests.zip
asset_name: orca_custom_preset_tests
asset_content_type: application/octet-stream
max_releases: 1
17 changes: 13 additions & 4 deletions .github/workflows/check_profiles.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Check locale
name: Check profiles
on:
pull_request:
branches:
Expand All @@ -19,12 +19,21 @@ jobs:
- name: Download
working-directory: ${{ github.workspace }}
run: |
curl -LJO https://github.com/SoftFever/Orca_tools/releases/download/1/OrcaSlicer_profile_validator_ubuntu
chmod +x ./OrcaSlicer_profile_validator_ubuntu
curl -LJO https://github.com/SoftFever/Orca_tools/releases/download/1/OrcaSlicer_profile_validator
chmod +x ./OrcaSlicer_profile_validator

# validate profiles
- name: validate profiles
- name: validate system profiles
run: |
./OrcaSlicer_profile_validator_ubuntu -p ${{ github.workspace }}/resources/profiles -l 2

- name: validate custom presets
working-directory: ${{ github.workspace }}
run: |
curl -LJO https://github.com/SoftFever/OrcaSlicer/releases/download/nightly-builds/orca_custom_preset_tests.zip
unzip ./orca_custom_preset_tests.zip -d ${{ github.workspace }}/resources/profiles
./OrcaSlicer_profile_validator_ubuntu -p ${{ github.workspace }}/resources/profiles -l 2




1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ src/OrcaSlicer-doc/
**/filament_full/
/deps/DL_CACHE/
/deps/DL_CACHE
resources/profiles/user/default
7 changes: 5 additions & 2 deletions BuildLinux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,16 @@ then

# cmake
pushd build
echo -e "cmake .. -DCMAKE_PREFIX_PATH=\"$PWD/../deps/build/destdir/usr/local\" -DSLIC3R_STATIC=1 ${BUILD_ARGS}"
cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local" -DSLIC3R_STATIC=1 ${BUILD_ARGS}
echo -e "cmake .. -DCMAKE_PREFIX_PATH=\"$PWD/../deps/build/destdir/usr/local\" -DSLIC3R_STATIC=1 -DORCA_TOOLS=ON ${BUILD_ARGS}"
cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local" -DSLIC3R_STATIC=1 ${BUILD_ARGS} -DORCA_TOOLS=ON
echo "done"

# make Slic3r
echo "[8/9] Building Slic3r..."
make -j$NCORES OrcaSlicer # Slic3r

# make OrcaSlicer_profile_validator
make -j$NCORES OrcaSlicer_profile_validator
popd
./run_gettext.sh
echo "done"
Expand Down
2 changes: 0 additions & 2 deletions resources/profiles/Elegoo/machine/fdm_neptune_4_common.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@
"deretraction_speed": [
"40"
],
"bridge_speed": "25",
"internal_bridge_speed" : "70",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"change_filament_gcode": "",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"bbl_calib_mark_logo": "1",
"setting_id": "GM003",
"name": "Kingroon KP3S PRO S1 0.4 nozzle",
"instantiation": "true",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"type": "machine",
"bbl_calib_mark_logo": "1",
"name": "fdm_machine_common",
"auxiliary_fan": "0",
"fan_kickstart": "0",
Expand Down
1 change: 0 additions & 1 deletion resources/profiles/Snapmaker/machine/fdm_common.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"auxiliary_fan": "0",
"remaining_times": "1",
"single_extruder_multi_material": "0",
"single_extruder_multi_material_priming": "0",
"purge_in_prime_tower": "0",
"enable_filament_ramming": "0",
"nozzle_volume": "0",
Expand Down
114 changes: 103 additions & 11 deletions src/OrcaSlicer_profile_validator.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,93 @@
#include "libslic3r/Preset.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/Utils.hpp"
#include <boost/filesystem/operations.hpp>
#include <boost/log/trivial.hpp>
#include <boost/program_options.hpp>
#include <iostream>
#include <string>

using namespace Slic3r;
namespace po = boost::program_options;

void generate_custom_presets(PresetBundle* preset_bundle, AppConfig& app_config)
{
struct cus_preset
{
std::string name;
std::string parent_name;
};
// create user presets
auto createCustomPrinters = [&](Preset::Type type) {
std::vector<cus_preset> custom_preset;
PresetCollection* collection = nullptr;
if (type == Preset::TYPE_PRINT)
collection = &preset_bundle->prints;
else if (type == Preset::TYPE_FILAMENT)
collection = &preset_bundle->filaments;
else if (type == Preset::TYPE_PRINTER)
collection = &preset_bundle->printers;
else
return;
custom_preset.reserve(collection->size());
for (auto& parent : collection->get_presets()) {
if (!parent.is_system)
continue;
auto new_name = parent.name + "_orca_test";
if (parent.vendor)
new_name = parent.vendor->name + "_" + new_name;
custom_preset.push_back({new_name, parent.name});
}
for (auto p : custom_preset) {
// Creating a new preset.
auto parent = collection->find_preset(p.parent_name);
if (type == Preset::TYPE_FILAMENT)
parent->config.set_key_value("filament_start_gcode",
new ConfigOptionStrings({"this_is_orca_test_filament_start_gcode_mock"}));
else if (type == Preset::TYPE_PRINT)
parent->config.set_key_value("filename_format", new ConfigOptionString("this_is_orca_test_filename_format_mock"));
else if (type == Preset::TYPE_PRINTER)
parent->config.set_key_value("machine_start_gcode",
new ConfigOptionString("this_is_orca_test_machine_start_gcode_mock"));

collection->save_current_preset(p.name, false, false, parent);

}
};
createCustomPrinters(Preset::TYPE_PRINTER);
createCustomPrinters(Preset::TYPE_FILAMENT);
createCustomPrinters(Preset::TYPE_PRINT);

std::string user_sub_folder = DEFAULT_USER_FOLDER_NAME;
const std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/" + user_sub_folder;

fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
if (!fs::exists(user_folder))
fs::create_directory(user_folder);

fs::path folder(dir_user_presets);
if (!fs::exists(folder))
fs::create_directory(folder);
std::vector<std::string> need_to_delete_list; // store setting ids of preset

preset_bundle->prints.save_user_presets(dir_user_presets, PRESET_PRINT_NAME, need_to_delete_list);
preset_bundle->filaments.save_user_presets(dir_user_presets, PRESET_FILAMENT_NAME, need_to_delete_list);
preset_bundle->printers.save_user_presets(dir_user_presets, PRESET_PRINTER_NAME, need_to_delete_list);

std::cout << "Custom presets generated successfully" << std::endl;
}
int main(int argc, char* argv[])
{
po::options_description desc("Allowed options");
po::options_description desc("Orca Profile Validator\nUsage");
// clang-format off
desc.add_options()("help,h", "help")
("path,p", po::value<std::string>()->default_value("../../../resources/profiles"), "profile folder")
("vendor,v", po::value<std::string>()->default_value(""),
"Vendor name. Optional, all profiles present in the folder will be validated if not specified")
("log_level,l", po::value<int>()->default_value(2),
"Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
("path,p", po::value<std::string>()->default_value("../../../resources/profiles"), "profile folder")
("vendor,v", po::value<std::string>()->default_value(""), "Vendor name. Optional, all profiles present in the folder will be validated if not specified")
("generate_presets,g", po::value<bool>()->default_value(false), "Generate user presets for mock test")
("log_level,l", po::value<int>()->default_value(2), "Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
// clang-format on

po::variables_map vm;
try {
Expand All @@ -34,30 +105,40 @@ int main(int argc, char* argv[])
return 1;
}

std::string path = vm["path"].as<std::string>();
std::string vendor = vm["vendor"].as<std::string>();
int log_level = vm["log_level"].as<int>();
std::string path = vm["path"].as<std::string>();
std::string vendor = vm["vendor"].as<std::string>();
int log_level = vm["log_level"].as<int>();
bool generate_user_preset = vm["generate_presets"].as<bool>();

// check if path is valid, and return error if not
if (!fs::exists(path) || !fs::is_directory(path)) {
std::cerr << "Error: " << path << " is not a valid directory\n";
return 1;
}


// std::cout<<"path: "<<path<<std::endl;
// std::cout<<"vendor: "<<vendor<<std::endl;
// std::cout<<"log_level: "<<log_level<<std::endl;

set_data_dir(path);

auto user_dir = fs::path(Slic3r::data_dir()) / PRESET_USER_DIR;
user_dir.make_preferred();
if (!fs::exists(user_dir))
fs::create_directory(user_dir);

set_logging_level(log_level);
auto preset_bundle = new PresetBundle();
preset_bundle->setup_directories();
// preset_bundle->setup_directories();
preset_bundle->set_is_validation_mode(true);
preset_bundle->set_vendor_to_validate(vendor);

preset_bundle->set_default_suppressed(true);
AppConfig app_config;
app_config.set("preset_folder", "default");

if(generate_user_preset)
preset_bundle->remove_user_presets_directory("default");

try {
auto preset_substitutions = preset_bundle->load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
Expand All @@ -66,6 +147,17 @@ int main(int argc, char* argv[])
std::cout << "Validation failed" << std::endl;
return 1;
}

if (generate_user_preset) {
generate_custom_presets(preset_bundle, app_config);
return 0;
}

if (preset_bundle->has_errors()) {
std::cout << "Validation failed" << std::endl;
return 1;
}

std::cout << "Validation completed successfully" << std::endl;
return 0;
}
41 changes: 29 additions & 12 deletions src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ void PresetCollection::load_presets(
if (fs::exists(file_path))
fs::remove(file_path);
BOOST_LOG_TRIVIAL(error) << boost::format("parse config %1% failed")%preset.file;
++m_errors;
continue;
}

Expand Down Expand Up @@ -1159,6 +1160,7 @@ void PresetCollection::load_presets(
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
if ((inherits_config2 && !inherits_config2->value.empty()) && !preset.is_custom_defined()) {
BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file;
++m_errors;
continue;
}
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
Expand All @@ -1169,16 +1171,20 @@ void PresetCollection::load_presets(
Preset::normalize(preset.config);
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
if (!incorrect_keys.empty())
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" <<
preset.file << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
if (!incorrect_keys.empty()) {
++m_errors;
BOOST_LOG_TRIVIAL(error)
<< "Error in a preset file: The preset \"" << preset.file
<< "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
}
preset.loaded = true;
//BBS: add some workaround for previous incorrect settings
if ((!preset.setting_id.empty())&&(preset.setting_id == preset.base_id))
preset.setting_id.clear();
//BBS: add config related logs
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", preset type %1%, name %2%, path %3%, is_system %4%, is_default %5% is_visible %6%")%Preset::get_type_string(m_type) %preset.name %preset.file %preset.is_system %preset.is_default %preset.is_visible;
} catch (const std::ifstream::failure &err) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << boost::format("The user-config cannot be loaded: %1%. Reason: %2%")%preset.file %err.what();
fs::path file_path(preset.file);
if (fs::exists(file_path))
Expand All @@ -1188,6 +1194,7 @@ void PresetCollection::load_presets(
fs::remove(file_path);
//throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
} catch (const std::runtime_error &err) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%")%preset.file %err.what();
//throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
fs::path file_path(preset.file);
Expand Down Expand Up @@ -1252,6 +1259,7 @@ int PresetCollection::get_differed_values_to_update(Preset& preset, std::map<std
{
if (preset.is_system || preset.is_default || preset.is_project_embedded) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" Error: not a user preset! Should not happen, name %1%") %preset.name;
++m_errors;
return -1;
}

Expand Down Expand Up @@ -1351,9 +1359,11 @@ void PresetCollection::load_project_embedded_presets(std::vector<Preset*>& proje
Preset::normalize(preset->config);
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(preset->config, default_preset.config);
if (! incorrect_keys.empty())
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" <<
preset->name << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
if (!incorrect_keys.empty()) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset->name
<< "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
}
preset->loaded = true;
presets_loaded.emplace_back(*preset);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", %1% got preset, name %2%, path %3%, is_system %4%, is_default %5% is_visible %6%")%Preset::get_type_string(m_type) %preset->name %preset->file %preset->is_system %preset->is_default %preset->is_visible;
Expand Down Expand Up @@ -1533,6 +1543,7 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std:
}
Preset* parent_preset = this->find_preset(inherits, false, true);
if (!parent_preset) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find parent preset for %1% , inherits %2%")%preset->name %inherits;
continue;
}
Expand Down Expand Up @@ -1680,9 +1691,11 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
Preset::normalize(new_config);
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(new_config, default_preset.config);
if (! incorrect_keys.empty())
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" <<
name << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
if (!incorrect_keys.empty()) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << name
<< "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
}
if (need_update) {
if (iter->name == m_edited_preset.name && iter->is_dirty) {
// Keep modifies when update from remote
Expand Down Expand Up @@ -2800,9 +2813,13 @@ void PresetCollection::update_map_system_profile_renamed()
for (Preset &preset : m_presets)
for (const std::string &renamed_from : preset.renamed_from) {
const auto [it, success] = m_map_system_profile_renamed.insert(std::pair<std::string, std::string>(renamed_from, preset.name));
if (! success)
BOOST_LOG_TRIVIAL(error) << boost::format("Preset name \"%1%\" was marked as renamed from \"%2%\", though preset name \"%3%\" was marked as renamed from \"%2%\" as well.") % preset.name % renamed_from % it->second;
}
if (!success) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << boost::format("Preset name \"%1%\" was marked as renamed from \"%2%\", though preset name "
"\"%3%\" was marked as renamed from \"%2%\" as well.") %
preset.name % renamed_from % it->second;
}
}
}

std::string PresetCollection::name() const
Expand Down
Loading
Loading