mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-22 18:32:16 +00:00
Compare commits
6 Commits
revert/rev
...
fix/plugin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc6ae243ca | ||
|
|
b121051220 | ||
|
|
242e100feb | ||
|
|
2a46bd1384 | ||
|
|
ddbbc7f7f2 | ||
|
|
3a48086f5d |
@@ -201,9 +201,12 @@ if (WIN32)
|
||||
if(MSVC)
|
||||
target_link_options(OrcaSlicer_app_gui PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
endif()
|
||||
target_compile_definitions(OrcaSlicer_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE)
|
||||
target_compile_definitions(OrcaSlicer_app_gui PRIVATE "$<$<NOT:$<CONFIG:RelWithDebInfo>>:SLIC3R_WRAPPER_NOCONSOLE>")
|
||||
add_dependencies(OrcaSlicer_app_gui OrcaSlicer)
|
||||
set_target_properties(OrcaSlicer_app_gui PROPERTIES OUTPUT_NAME "orca-slicer")
|
||||
set_target_properties(OrcaSlicer_app_gui PROPERTIES
|
||||
OUTPUT_NAME "orca-slicer"
|
||||
WIN32_EXECUTABLE "$<NOT:$<CONFIG:RelWithDebInfo>>"
|
||||
)
|
||||
target_link_libraries(OrcaSlicer_app_gui PRIVATE boost_headeronly)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -535,6 +535,7 @@ endif ()
|
||||
encoding_check(libslic3r)
|
||||
|
||||
target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0)
|
||||
target_compile_definitions(libslic3r PRIVATE $<$<CONFIG:RelWithDebInfo>:SLIC3R_CONSOLE_LOG>)
|
||||
target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_include_directories(libslic3r SYSTEM PUBLIC ${EXPAT_INCLUDE_DIRS})
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ std::string debug_out_path(const char *name, ...);
|
||||
// smaller level means less log. level=5 means saving all logs.
|
||||
void set_log_path_and_level(const std::string& file, unsigned int level);
|
||||
void flush_logs();
|
||||
void shutdown_console_logging();
|
||||
boost::filesystem::path get_log_file_name();
|
||||
|
||||
// A special type for strings encoded in the local Windows 8-bit code page.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <locale>
|
||||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
@@ -50,14 +51,19 @@
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/sinks/async_frontend.hpp>
|
||||
#include <boost/log/sinks/text_file_backend.hpp>
|
||||
#include <boost/log/sinks/text_ostream_backend.hpp>
|
||||
#include <boost/log/utility/setup/file.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
#include <boost/log/sources/severity_logger.hpp>
|
||||
#include <boost/log/sources/record_ostream.hpp>
|
||||
#include <boost/log/support/date_time.hpp>
|
||||
|
||||
#include <boost/core/null_deleter.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -178,6 +184,7 @@ unsigned get_logging_level()
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend>> g_log_sink;
|
||||
boost::shared_ptr<boost::log::sinks::asynchronous_sink<boost::log::sinks::text_ostream_backend>> g_console_log_sink;
|
||||
|
||||
// Force set_logging_level(<=error) after loading of the DLL.
|
||||
// This is currently only needed if libslic3r is loaded as a shared library into Perl interpreter
|
||||
@@ -350,6 +357,19 @@ namespace src = boost::log::sources;
|
||||
namespace expr = boost::log::expressions;
|
||||
namespace keywords = boost::log::keywords;
|
||||
namespace attrs = boost::log::attributes;
|
||||
namespace sinks = boost::log::sinks;
|
||||
|
||||
void shutdown_console_logging()
|
||||
{
|
||||
if (!g_console_log_sink)
|
||||
return;
|
||||
|
||||
auto console_sink = g_console_log_sink;
|
||||
boost::log::core::get()->remove_sink(console_sink);
|
||||
console_sink->stop();
|
||||
g_console_log_sink.reset();
|
||||
}
|
||||
|
||||
void set_log_path_and_level(const std::string& file, unsigned int level)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
@@ -381,6 +401,24 @@ void set_log_path_and_level(const std::string& file, unsigned int level)
|
||||
keywords::auto_flush = true
|
||||
);
|
||||
|
||||
shutdown_console_logging();
|
||||
|
||||
#ifdef SLIC3R_CONSOLE_LOG
|
||||
auto console_backend = boost::make_shared<sinks::text_ostream_backend>();
|
||||
console_backend->add_stream(boost::shared_ptr<std::ostream>(&std::cout, boost::null_deleter()));
|
||||
console_backend->auto_flush(true);
|
||||
|
||||
g_console_log_sink = boost::make_shared<sinks::asynchronous_sink<sinks::text_ostream_backend>>(console_backend);
|
||||
g_console_log_sink->set_formatter(
|
||||
expr::stream
|
||||
<< "[" << expr::attr< logging::trivial::severity_level >("Severity") << "]\t"
|
||||
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " "
|
||||
<<"[Thread " << expr::attr<attrs::current_thread_id::value_type>("ThreadID") << "]"
|
||||
<< ": " << expr::smessage
|
||||
);
|
||||
boost::log::core::get()->add_sink(g_console_log_sink);
|
||||
#endif
|
||||
|
||||
logging::add_common_attributes();
|
||||
|
||||
set_logging_level(level);
|
||||
|
||||
@@ -2355,6 +2355,7 @@ GUI_App::~GUI_App()
|
||||
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": exit");
|
||||
shutdown_console_logging();
|
||||
}
|
||||
|
||||
bool GUI_App::is_blocking_printing(MachineObject *obj_)
|
||||
|
||||
@@ -48,13 +48,14 @@ std::string plugin_defaults_user_script()
|
||||
return WebViewHostDialog::document_start_injector(css, "orca-plugin-defaults", "beforeend");
|
||||
}
|
||||
|
||||
// Injected into every page at document start (before the plugin's own scripts).
|
||||
// Defines window.orca as the only host surface the page may use. It references
|
||||
// window.wx lazily (at call time) so it never races the backend's deferred
|
||||
// registration of the "wx" message handler. Guarded against double-injection so
|
||||
// it is harmless if also prepended.
|
||||
// Injected into the top-level page at document start (before the plugin's own
|
||||
// scripts). Defines window.orca as the only host surface the page may use. It
|
||||
// references window.wx lazily (at call time) so it never races the backend's
|
||||
// deferred registration of the "wx" message handler. Guarded against
|
||||
// double-injection so it is harmless if also prepended.
|
||||
constexpr char ORCA_BRIDGE_JS[] = R"JS(
|
||||
(function () {
|
||||
if (window.top !== window.self) return;
|
||||
if (window.orca) return;
|
||||
var handlers = [];
|
||||
function send(kind, data) {
|
||||
|
||||
@@ -300,7 +300,12 @@ PluginAvailableActions evaluate_action_policy(const PluginDialogItem& item)
|
||||
|
||||
add_action("open_folder", "Show in folder", has_local);
|
||||
|
||||
add_action("reinstall_plugin", "Reinstall");
|
||||
if (is_cloud) {
|
||||
add_action("reinstall_plugin", "Reinstall");
|
||||
} else {
|
||||
add_action("reload_plugin", "Reload");
|
||||
add_action("clear_cache_reload_plugin", "Delete cache and reload");
|
||||
}
|
||||
|
||||
return available_actions;
|
||||
}
|
||||
@@ -739,11 +744,13 @@ void PluginsDialog::handle_plugin_menu_action(const std::string& plugin_key, con
|
||||
unsubscribe_cloud_plugin(row_data);
|
||||
} else if (action == "delete_mine_plugin") {
|
||||
delete_mine_local_and_cloud_plugin(plugin_key);
|
||||
} else if (action == "reload_plugin") {
|
||||
reload_local_plugin(plugin_key, /*clear_cache=*/false);
|
||||
} else if (action == "clear_cache_reload_plugin") {
|
||||
reload_local_plugin(plugin_key, /*clear_cache=*/true);
|
||||
} else if (action == "reinstall_plugin") {
|
||||
if (row_data.is_cloud_plugin())
|
||||
reinstall_cloud_plugin(row_data);
|
||||
else
|
||||
reinstall_local_plugin(plugin_key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1123,7 +1130,7 @@ void PluginsDialog::unsubscribe_cloud_plugin(const PluginDescriptor& plugin)
|
||||
_L("Unsubscribing plugin"), _L("Deleting local files and unsubscribing plugin..."));
|
||||
}
|
||||
|
||||
void PluginsDialog::reinstall_local_plugin(const std::string& plugin_key)
|
||||
void PluginsDialog::reload_local_plugin(const std::string& plugin_key, bool clear_cache)
|
||||
{
|
||||
if (plugin_key.empty())
|
||||
return;
|
||||
@@ -1132,11 +1139,34 @@ void PluginsDialog::reinstall_local_plugin(const std::string& plugin_key)
|
||||
std::pair<bool, std::string> reload_result{false, ""};
|
||||
try {
|
||||
reload_result = run_with_dialog_wait(
|
||||
[plugin_key, was_loaded]() -> std::pair<bool, std::string> {
|
||||
[plugin_key, was_loaded, clear_cache]() -> std::pair<bool, std::string> {
|
||||
PluginManager& manager = PluginManager::instance();
|
||||
|
||||
boost::filesystem::path cache_dir;
|
||||
if (clear_cache) {
|
||||
PluginDescriptor descriptor;
|
||||
if (!manager.try_get_plugin_descriptor(plugin_key, descriptor))
|
||||
return {false, "Plugin not found."};
|
||||
|
||||
boost::filesystem::path resolved_root;
|
||||
std::string resolve_error;
|
||||
if (!resolve_allowed_plugin_root(descriptor, {get_orca_plugins_dir()},
|
||||
"Refusing to clear a plugin cache outside the local plugin directory.",
|
||||
resolved_root, resolve_error))
|
||||
return {false, resolve_error};
|
||||
cache_dir = resolved_root / "__whl_extracted__";
|
||||
}
|
||||
|
||||
if (!manager.unload_plugin(plugin_key))
|
||||
return {false, "Failed to unload plugin."};
|
||||
|
||||
if (clear_cache) {
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove_all(cache_dir, ec);
|
||||
if (ec)
|
||||
return {false, "Failed to clear plugin cache: " + ec.message()};
|
||||
}
|
||||
|
||||
manager.load_plugin(plugin_key, false);
|
||||
std::string error;
|
||||
if (!manager.wait_for_plugin_load(plugin_key, std::chrono::minutes(5), error) || !manager.is_plugin_loaded(plugin_key))
|
||||
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
void open_plugin_folder(const Slic3r::PluginDescriptor& plugin);
|
||||
void delete_local_plugin(const Slic3r::PluginDescriptor& plugin);
|
||||
void unsubscribe_cloud_plugin(const Slic3r::PluginDescriptor& plugin);
|
||||
void reinstall_local_plugin(const std::string& plugin_key);
|
||||
void reload_local_plugin(const std::string& plugin_key, bool clear_cache);
|
||||
void reinstall_cloud_plugin(const Slic3r::PluginDescriptor& plugin);
|
||||
void delete_mine_local_and_cloud_plugin(const std::string& plugin_key);
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ std::string WebViewHostDialog::document_start_injector(const std::string& markup
|
||||
const std::string literal = nlohmann::json(markup).dump();
|
||||
std::string s;
|
||||
s += "(function(){";
|
||||
// wxWebView's AddUserScript runs in child frames too (including cross-origin
|
||||
// frames on WebView2). Host theme state belongs only to the top-level page.
|
||||
s += "if(window.top!==window.self)return;";
|
||||
s += prelude;
|
||||
s += "var css=" + literal + ";";
|
||||
s += "function inject(){";
|
||||
|
||||
@@ -54,7 +54,7 @@ struct PluginDescriptor
|
||||
std::string description; // Plugin description
|
||||
std::string author; // Plugin author from manifest, if available
|
||||
std::string version; // Selected plugin version
|
||||
std::string latest_version; // Latest available cloud version fallback when changelog is unavailable.
|
||||
std::string latest_version; // Authoritative latest available cloud version.
|
||||
std::string installed_version; // Locally installed package version. Preserved across cloud merges, which overwrite `version` with the latest cloud version. Empty when not installed.
|
||||
std::vector<std::string> display_types; // Display-only "compatibility" labels (cloud: raw service labels; local: from real capabilities). Never used for dispatch.
|
||||
std::string plugin_root; // Installed plugin directory, even when entry_path is invalid or ambiguous.
|
||||
@@ -113,10 +113,6 @@ struct PluginDescriptor
|
||||
bool is_unauthorized() const { return get_update_status() == PluginUpdateStatus::Unauthorized; }
|
||||
std::string latest_available_version() const
|
||||
{
|
||||
for (const PluginChangelog& entry : changelog) {
|
||||
if (!entry.version.empty())
|
||||
return entry.version;
|
||||
}
|
||||
if (!latest_version.empty())
|
||||
return latest_version;
|
||||
return version;
|
||||
|
||||
@@ -52,6 +52,29 @@ print('ok')
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("plugin latest version uses the authoritative catalog field", "[PluginDescriptor]")
|
||||
{
|
||||
PluginDescriptor descriptor;
|
||||
descriptor.version = "1.3.0";
|
||||
descriptor.latest_version = "1.3.0";
|
||||
PluginChangelog changelog;
|
||||
changelog.version = "1.2.0";
|
||||
descriptor.changelog.push_back(changelog);
|
||||
|
||||
CHECK(descriptor.latest_available_version() == "1.3.0");
|
||||
}
|
||||
|
||||
TEST_CASE("plugin latest version falls back to the descriptor version", "[PluginDescriptor]")
|
||||
{
|
||||
PluginDescriptor descriptor;
|
||||
descriptor.version = "1.1.0";
|
||||
PluginChangelog changelog;
|
||||
changelog.version = "1.0.0";
|
||||
descriptor.changelog.push_back(changelog);
|
||||
|
||||
CHECK(descriptor.latest_available_version() == "1.1.0");
|
||||
}
|
||||
|
||||
// Regression: update_cloud_metadata() replaces a matched entry's descriptor wholesale with the
|
||||
// cloud catalog record (`entry = cloud_entry`). Configuration used to ride on the descriptor, so
|
||||
// that overwrite silently wiped it and plugins fell back to their built-in defaults (found via
|
||||
|
||||
Reference in New Issue
Block a user