Refactored command executors (better naming, documentation).

This commit is contained in:
Alexander Shaduri
2021-03-16 15:24:08 +04:00
parent cfc11bef6e
commit d74da816a1
31 changed files with 696 additions and 546 deletions
+3 -2
View File
@@ -20,8 +20,9 @@ src/gsc_preferences_window.cpp
src/gsc_text_window.h
src/applib/app_builder_widget.h
src/applib/cli_executors.h
src/applib/cmdex_sync_gui.cpp
src/applib/cli_executor_3ware.h
src/applib/cli_executor_areca.h
src/applib/command_executor_gui.cpp
src/applib/selftest.cpp
src/applib/smartctl_executor.cpp
src/applib/smartctl_executor.h
+10 -9
View File
@@ -7,20 +7,21 @@
add_library(applib STATIC)
target_sources(applib PRIVATE
async_command_executor.cpp
async_command_executor.h
app_builder_widget.h
app_gtkmm_features.h
app_gtkmm_utils.cpp
app_gtkmm_utils.h
app_pcrecpp.h
cli_executors.h
cmdex.cpp
cmdex.h
cmdex_sync.cpp
cmdex_sync_gui.cpp
cmdex_sync_gui.h
cmdex_sync.h
executor_factory.cpp
executor_factory.h
command_executor.h
command_executor.cpp
command_executor_3ware.h
command_executor_areca.h
command_executor_gui.cpp
command_executor_gui.h
command_executor_factory.cpp
command_executor_factory.h
gui_utils.cpp
gui_utils.h
selftest.cpp
@@ -9,7 +9,6 @@ Copyright:
/// \weakgroup applib
/// @{
// TODO Remove this in gtkmm4.
#include "local_glibmm.h"
#include <string>
@@ -28,7 +27,7 @@ Copyright:
#include "hz/debug.h"
#include "hz/env_tools.h" // hz::ScopedEnv
#include "cmdex.h"
#include "async_command_executor.h"
using hz::Error;
@@ -46,21 +45,21 @@ extern "C" {
/// Child process watcher callback
inline void cmdex_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data)
{
Cmdex::on_child_watch_handler(arg_pid, waitpid_status, data);
AsyncCommandExecutor::on_child_watch_handler(arg_pid, waitpid_status, data);
}
/// Child process stdout handler callback
inline gboolean cmdex_on_channel_io_stdout(GIOChannel* source, GIOCondition cond, gpointer data)
{
return Cmdex::on_channel_io(source, cond, static_cast<Cmdex*>(data), Cmdex::Channel::standard_output);
return AsyncCommandExecutor::on_channel_io(source, cond, static_cast<AsyncCommandExecutor*>(data), AsyncCommandExecutor::Channel::standard_output);
}
/// Child process stderr handler callback
inline gboolean cmdex_on_channel_io_stderr(GIOChannel* source, GIOCondition cond, gpointer data)
{
return Cmdex::on_channel_io(source, cond, static_cast<Cmdex*>(data), Cmdex::Channel::standard_error);
return AsyncCommandExecutor::on_channel_io(source, cond, static_cast<AsyncCommandExecutor*>(data), AsyncCommandExecutor::Channel::standard_error);
}
@@ -68,7 +67,7 @@ extern "C" {
inline gboolean cmdex_on_term_timeout(gpointer data)
{
DBG_FUNCTION_ENTER_MSG;
auto* self = static_cast<Cmdex*>(data);
auto* self = static_cast<AsyncCommandExecutor*>(data);
self->try_stop(hz::Signal::Terminate);
return FALSE; // one-time call
}
@@ -78,7 +77,7 @@ extern "C" {
inline gboolean cmdex_on_kill_timeout(gpointer data)
{
DBG_FUNCTION_ENTER_MSG;
auto* self = static_cast<Cmdex*>(data);
auto* self = static_cast<AsyncCommandExecutor*>(data);
self->try_stop(hz::Signal::Kill);
return FALSE; // one-time call
}
@@ -90,8 +89,36 @@ extern "C" {
AsyncCommandExecutor::AsyncCommandExecutor(AsyncCommandExecutor::exited_callback_func_t exited_cb)
: timer_(g_timer_new()),
exited_callback_(std::move(exited_cb))
{ }
bool Cmdex::execute()
AsyncCommandExecutor::~AsyncCommandExecutor()
{
// This will help if object is destroyed after the command has exited, but before
// stopped_cleanup() has been called.
stopped_cleanup();
g_timer_destroy(timer_);
// no need to destroy the channels - stopped_cleanup() calls
// cleanup_members(), which deletes them.
}
void AsyncCommandExecutor::set_command(const std::string& command_exec, const std::string& command_args)
{
command_exec_ = command_exec;
command_args_ = command_args;
}
bool AsyncCommandExecutor::execute()
{
DBG_FUNCTION_ENTER_MSG;
if (this->running_ || this->stopped_cleanup_needed()) {
@@ -213,9 +240,7 @@ bool Cmdex::execute()
// send SIGTERM(15) (terminate)
bool Cmdex::try_stop(hz::Signal sig)
bool AsyncCommandExecutor::try_stop(hz::Signal sig)
{
DBG_FUNCTION_ENTER_MSG;
if (!this->running_ || this->pid_ == 0)
@@ -239,7 +264,7 @@ bool Cmdex::try_stop(hz::Signal sig)
bool Cmdex::try_kill()
bool AsyncCommandExecutor::try_kill()
{
DBG_TRACE_POINT_AUTO;
return try_stop(hz::Signal::Kill);
@@ -247,7 +272,7 @@ bool Cmdex::try_kill()
void Cmdex::set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::chrono::milliseconds kill_timeout_msec)
void AsyncCommandExecutor::set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::chrono::milliseconds kill_timeout_msec)
{
DBG_FUNCTION_ENTER_MSG;
DBG_ASSERT(term_timeout_msec.count() == 0 || kill_timeout_msec.count() == 0 || kill_timeout_msec > term_timeout_msec);
@@ -268,8 +293,7 @@ void Cmdex::set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::
void Cmdex::unset_stop_timeouts()
void AsyncCommandExecutor::unset_stop_timeouts()
{
DBG_FUNCTION_ENTER_MSG;
if (event_source_id_term != 0) {
@@ -290,8 +314,7 @@ void Cmdex::unset_stop_timeouts()
// Executed manually by the caller.
void Cmdex::stopped_cleanup()
void AsyncCommandExecutor::stopped_cleanup()
{
DBG_FUNCTION_ENTER_MSG;
if (this->running_ || !this->stopped_cleanup_needed()) // huh?
@@ -335,13 +358,10 @@ void Cmdex::stopped_cleanup()
// Called when child exits
void Cmdex::on_child_watch_handler([[maybe_unused]] GPid arg_pid, int waitpid_status, gpointer data)
void AsyncCommandExecutor::on_child_watch_handler([[maybe_unused]] GPid arg_pid, int waitpid_status, gpointer data)
{
// DBG_FUNCTION_ENTER_MSG;
auto* self = static_cast<Cmdex*>(data);
auto* self = static_cast<AsyncCommandExecutor*>(data);
g_timer_stop(self->timer_); // stop the timer
@@ -396,13 +416,11 @@ void Cmdex::on_child_watch_handler([[maybe_unused]] GPid arg_pid, int waitpid_st
gboolean Cmdex::on_channel_io(GIOChannel* channel,
GIOCondition cond, Cmdex* self, Channel channel_type)
gboolean AsyncCommandExecutor::on_channel_io(GIOChannel* channel,
GIOCondition cond, AsyncCommandExecutor* self, Channel channel_type)
{
// DBG_FUNCTION_ENTER_MSG;
// debug_out_dump("app", "Cmdex::on_channel_io("
// debug_out_dump("app", "AsyncCommandExecutor::on_channel_io("
// << (type == Channel::standard_output ? "STDOUT" : "STDERR") << ") " << int(cond) << "\n");
bool continue_events = true;
@@ -456,7 +474,80 @@ gboolean Cmdex::on_channel_io(GIOChannel* channel,
void Cmdex::cleanup_members()
bool AsyncCommandExecutor::stopped_cleanup_needed()
{
return (child_watch_handler_called_);
}
bool AsyncCommandExecutor::is_running() const
{
return running_;
}
void AsyncCommandExecutor::set_buffer_sizes(gsize stdout_buffer_size, gsize stderr_buffer_size)
{
if (stdout_buffer_size > 0) {
channel_stdout_buffer_size_ = stdout_buffer_size; // 100K by default
}
if (stderr_buffer_size > 0) {
channel_stderr_buffer_size_ = stderr_buffer_size; // 10K by default
}
}
std::string AsyncCommandExecutor::get_stdout_str(bool clear_existing)
{
// debug_out_dump("app", str_stdout_);
if (clear_existing) {
std::string ret = str_stdout_;
str_stdout_.clear();
return ret;
}
return str_stdout_;
}
std::string AsyncCommandExecutor::get_stderr_str(bool clear_existing)
{
if (clear_existing) {
std::string ret = str_stderr_;
str_stderr_.clear();
return ret;
}
return str_stderr_;
}
double AsyncCommandExecutor::get_execution_time_sec()
{
gulong microsec = 0;
return g_timer_elapsed(timer_, &microsec);
}
void AsyncCommandExecutor::set_exit_status_translator(AsyncCommandExecutor::exit_status_translator_func_t func)
{
translator_func_ = std::move(func);
}
void AsyncCommandExecutor::set_exited_callback(AsyncCommandExecutor::exited_callback_func_t func)
{
exited_callback_ = std::move(func);
}
void AsyncCommandExecutor::cleanup_members()
{
kill_signal_sent_ = 0;
child_watch_handler_called_ = false;
@@ -4,8 +4,8 @@ Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
#ifndef APP_CMDEX_H
#define APP_CMDEX_H
#ifndef ASYNC_COMMAND_EXECUTOR_H
#define ASYNC_COMMAND_EXECUTOR_H
#include <glib.h>
#include <string>
@@ -22,7 +22,7 @@ Copyright:
/// 1. Add a callback to signal_exited.
/// 2. Manually poll stopped_cleanup_needed().
/// In both cases, stopped_cleanup() must be called afterwards.
class Cmdex : public hz::ErrorHolder {
class AsyncCommandExecutor : public hz::ErrorHolder {
public:
/// A function that translates the exit error code into a readable string
@@ -33,37 +33,31 @@ class Cmdex : public hz::ErrorHolder {
/// Constructor
explicit Cmdex(exited_callback_func_t exited_cb = nullptr)
: timer_(g_timer_new()),
exited_callback_(std::move(exited_cb))
{ }
explicit AsyncCommandExecutor(exited_callback_func_t exited_cb = nullptr);
/// Deleted
AsyncCommandExecutor(const AsyncCommandExecutor& other) = delete;
/// Deleted
AsyncCommandExecutor(const AsyncCommandExecutor&& other) = delete;
/// Deleted
AsyncCommandExecutor& operator=(const AsyncCommandExecutor& other) = delete;
/// Deleted
AsyncCommandExecutor& operator=(const AsyncCommandExecutor&& other) = delete;
/// Destructor. Don't destroy this object unless the child has exited. It will leak stuff
/// and possibly crash, etc... .
~Cmdex() override
{
// This will help if object is destroyed after the command has exited, but before
// stopped_cleanup() has been called.
stopped_cleanup();
g_timer_destroy(timer_);
// no need to destroy the channels - stopped_cleanup() calls
// cleanup_members(), which deletes them.
}
~AsyncCommandExecutor() override;
/// Set the command to execute. Call before execute().
/// Note: The command and the arguments _must_ be shell-escaped.
/// Use g_shell_quote() or Glib::shell_quote(). Note that each argument
/// must be escaped separately.
void set_command(const std::string& command_exec, const std::string& command_args)
{
command_exec_ = command_exec;
command_args_ = command_args;
}
void set_command(const std::string& command_exec, const std::string& command_args);
/// Launch the command.
@@ -92,7 +86,6 @@ class Cmdex : public hz::ErrorHolder {
/// This has an effect only if the command is running (after execute()).
void unset_stop_timeouts();
/// If stopped_cleanup_needed() returned true, call this. The command
/// should be exited by this time. Must be called before the next execute().
void stopped_cleanup();
@@ -101,19 +94,13 @@ class Cmdex : public hz::ErrorHolder {
/// Returns true if command has stopped.
/// Call repeatedly in a waiting function, after execute().
/// When it returns true, call stopped_cleanup().
bool stopped_cleanup_needed()
{
return (child_watch_handler_called_);
}
bool stopped_cleanup_needed();
/// Check if the process is running. Note that if this returns false, it doesn't mean that
/// the io channels have been closed or that the data may be read safely. Poll
/// stopped_cleanup_needed() instead.
[[nodiscard]] bool is_running() const
{
return running_;
}
[[nodiscard]] bool is_running() const;
@@ -129,69 +116,36 @@ class Cmdex : public hz::ErrorHolder {
/// Another way is to delay the command exit so that the event source callback
/// catches on and reads the buffer.
// Use 0 to ignore the parameter. Call this before execute().
void set_buffer_sizes(gsize stdout_buffer_size = 0, gsize stderr_buffer_size = 0)
{
if (stdout_buffer_size)
channel_stdout_buffer_size_ = stdout_buffer_size; // 100K by default
if (stderr_buffer_size)
channel_stderr_buffer_size_ = stderr_buffer_size; // 10K by default
}
void set_buffer_sizes(gsize stdout_buffer_size = 0, gsize stderr_buffer_size = 0);
/// If stdout_make_str_as_available_ is false, call this after stopped_cleanup(),
/// before next execute(). If it's true, you may call this before the command has
/// stopped, but it will decrease performance significantly.
std::string get_stdout_str(bool clear_existing = false)
{
// debug_out_dump("app", str_stdout_);
if (clear_existing) {
std::string ret = str_stdout_;
str_stdout_.clear();
return ret;
}
return str_stdout_;
}
std::string get_stdout_str(bool clear_existing = false);
/// See notes on get_stdout_str().
std::string get_stderr_str(bool clear_existing = false)
{
if (clear_existing) {
std::string ret = str_stderr_;
str_stderr_.clear();
return ret;
}
return str_stderr_;
}
/// See notes for \ref get_stdout_str().
std::string get_stderr_str(bool clear_existing = false);
/// Return execution time, in seconds. Call this after execute().
double get_execution_time()
{
gulong microsec = 0;
return g_timer_elapsed(timer_, &microsec);
}
[[maybe_unused]] double get_execution_time_sec();
/// Set exit status translator callback, disconnecting the old one.
/// Call only before execute().
void set_exit_status_translator(exit_status_translator_func_t func)
{
translator_func_ = std::move(func);
}
void set_exit_status_translator(exit_status_translator_func_t func);
/// Set exit notifier callback, disconnecting the old one.
/// You can poll stopped_cleanup_needed() instead of using this function.
void set_exited_callback(exited_callback_func_t func)
{
exited_callback_ = std::move(func);
}
void set_exited_callback(exited_callback_func_t func);
// these are sorta-private
// these are sort of private
/// Channel type, for passing to callbacks
enum class Channel {
@@ -206,7 +160,7 @@ class Cmdex : public hz::ErrorHolder {
static void on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data);
/// Channel I/O handler
static gboolean on_channel_io(GIOChannel* channel, GIOCondition cond, Cmdex* self, Channel channel_type);
static gboolean on_channel_io(GIOChannel* channel, GIOCondition cond, AsyncCommandExecutor* self, Channel channel_type);
private:
@@ -218,8 +172,8 @@ class Cmdex : public hz::ErrorHolder {
// default command and its args. std::strings, not ustrings.
std::string command_exec_{ }; /// Binary name to execute. NOT affected by cleanup_members().
std::string command_args_{ }; /// Arguments that always go with the binary. NOT affected by cleanup_members().
std::string command_exec_; /// Binary name to execute. NOT affected by cleanup_members().
std::string command_args_; /// Arguments that always go with the binary. NOT affected by cleanup_members().
bool running_ = false; ///< If true, the child process is running now. NOT affected by cleanup_members().
@@ -248,8 +202,8 @@ class Cmdex : public hz::ErrorHolder {
guint event_source_id_stdout_ = 0; ///< IO watcher event source ID for stdout
guint event_source_id_stderr_ = 0; ///< IO watcher event source ID for stderr
std::string str_stdout_{ }; ///< stdout data read during execution. NOT affected by cleanup_members().
std::string str_stderr_{ }; ///< stderr data read during execution. NOT affected by cleanup_members().
std::string str_stdout_; ///< stdout data read during execution. NOT affected by cleanup_members().
std::string str_stderr_; ///< stderr data read during execution. NOT affected by cleanup_members().
// signals
-223
View File
@@ -1,223 +0,0 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#ifndef CLI_EXECUTORS_H
#define CLI_EXECUTORS_H
#include "local_glibmm.h"
#include "cmdex.h"
#include "cmdex_sync.h"
/// Executor for tw_cli (3ware utility)
template<class ExecutorSync>
class TwCliExecutorGeneric : public ExecutorSync {
public:
/// Constructor
TwCliExecutorGeneric(const std::string& cmd, const std::string& cmdargs)
: ExecutorSync(cmd, cmdargs)
{
this->construct();
}
/// Constructor
TwCliExecutorGeneric()
{
this->construct();
}
/// Virtual destructor
virtual ~TwCliExecutorGeneric() = default;
protected:
/// Called from constructors
void construct()
{
ExecutorSync::get_command_executor().set_exit_status_translator(&TwCliExecutorGeneric::translate_exit_status);
this->set_error_header(std::string(_("An error occurred while executing tw_cli:")) + "\n\n");
}
/// Exit status translate handler
static std::string translate_exit_status([[maybe_unused]] int status)
{
return std::string();
}
/// Import the last error from command executor and clear all errors there
void import_error() override
{
Cmdex& cmdex = this->get_command_executor();
Cmdex::error_list_t errors = cmdex.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
// find the last relevant error.
for (auto iter = errors.crbegin(); iter != errors.crend(); ++iter) {
// ignore iochannel errors, they may mask the real errors
if ((*iter)->get_type() != "giochannel" && (*iter)->get_type() != "custom") {
e = (*iter)->clone();
break;
}
}
cmdex.clear_errors(); // and clear them
if (e) { // if error is present, alert the user
on_error_warn(e);
}
}
/// This is called when an error occurs in command executor.
/// Note: The warnings are already printed via debug_* in cmdex.
void on_error_warn(hz::ErrorBase* e) override
{
if (!e)
return;
// import the error only if it's relevant.
std::string error_type = e->get_type();
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
if (error_type == "giochannel" || error_type == "custom") {
return;
}
this->set_error_msg(e->get_message());
}
};
/// tw_cli executor without GUI support
using TwCliExecutor = TwCliExecutorGeneric<CmdexSync>;
/// tw_cli executor with GUI support
using TwCliExecutorGui = TwCliExecutorGeneric<CmdexSyncGui>;
/// Executor for cli (Areca utility)
template<class ExecutorSync>
class ArecaCliExecutorGeneric : public ExecutorSync {
public:
/// Constructor
ArecaCliExecutorGeneric(const std::string& cmd, const std::string& cmdargs)
: ExecutorSync(cmd, cmdargs)
{
this->construct();
}
/// Constructor
ArecaCliExecutorGeneric()
{
this->construct();
}
/// Virtual destructor
virtual ~ArecaCliExecutorGeneric() = default;
protected:
/// Called from constructors
void construct()
{
ExecutorSync::get_command_executor().set_exit_status_translator(&ArecaCliExecutorGeneric::translate_exit_status);
this->set_error_header(std::string(_("An error occurred while executing Areca cli:")) + "\n\n");
}
/// Exit status translate handler
static std::string translate_exit_status([[maybe_unused]] int status)
{
return std::string();
}
/// Import the last error from command executor and clear all errors there
void import_error() override
{
Cmdex& cmdex = this->get_command_executor();
Cmdex::error_list_t errors = cmdex.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
// find the last relevant error.
for (auto iter = errors.crbegin(); iter != errors.crend(); ++iter) {
// ignore iochannel errors, they may mask the real errors
if ((*iter)->get_type() != "giochannel" && (*iter)->get_type() != "custom") {
e = (*iter)->clone();
break;
}
}
cmdex.clear_errors(); // and clear them
if (e) { // if error is present, alert the user
on_error_warn(e);
}
}
/// This is called when an error occurs in command executor.
/// Note: The warnings are already printed via debug_* in cmdex.
void on_error_warn(hz::ErrorBase* e) override
{
if (!e)
return;
// import the error only if it's relevant.
std::string error_type = e->get_type();
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
if (error_type == "giochannel" || error_type == "custom") {
return;
}
this->set_error_msg(e->get_message());
}
};
/// tw_cli executor without GUI support
using ArecaCliExecutor = ArecaCliExecutorGeneric<CmdexSync>;
/// tw_cli executor with GUI support
using ArecaCliExecutorGui = ArecaCliExecutorGeneric<CmdexSyncGui>;
#endif
/// @}
@@ -12,28 +12,28 @@ Copyright:
#include "local_glibmm.h"
#include <glib.h> // g_usleep()
#include "cmdex_sync.h"
#include "command_executor.h"
cmdex_signal_execute_finish_type& cmdex_sync_signal_execute_finish()
cmdex_signal_execute_finish_t& cmdex_sync_signal_execute_finish()
{
/// "Execution finished" signal
static sigc::signal<void, const CmdexSyncCommandInfo&> s_cmdex_sync_signal_execute_finish;
static sigc::signal<void, const CommandExecutorResult&> s_cmdex_sync_signal_execute_finish;
return s_cmdex_sync_signal_execute_finish;
}
CmdexSync::CmdexSync(std::string command_name, std::string command_args)
: CmdexSync()
CommandExecutor::CommandExecutor(std::string command_name, std::string command_args)
: CommandExecutor()
{
this->set_command(std::move(command_name), std::move(command_args));
}
CmdexSync::CmdexSync()
CommandExecutor::CommandExecutor()
{
/// Translators: {command} will be replaced by command name.
running_msg_ = _("Running {command}...");
@@ -42,7 +42,7 @@ CmdexSync::CmdexSync()
void CmdexSync::set_command(std::string command_name, std::string command_args)
void CommandExecutor::set_command(std::string command_name, std::string command_args)
{
cmdex_.set_command(command_name, command_args);
// keep a copy locally to avoid locking on get() every time
@@ -52,27 +52,27 @@ void CmdexSync::set_command(std::string command_name, std::string command_args)
std::string CmdexSync::get_command_name() const
std::string CommandExecutor::get_command_name() const
{
return command_name_;
}
std::string CmdexSync::get_command_args() const
std::string CommandExecutor::get_command_args() const
{
return command_args_;
}
bool CmdexSync::execute()
bool CommandExecutor::execute()
{
set_error_msg(""); // clear old error if present
bool slot_connected = !(signal_execute_tick.slots().begin() == signal_execute_tick.slots().end());
bool slot_connected = !(signal_execute_tick().slots().begin() == signal_execute_tick().slots().end());
if (slot_connected && !signal_execute_tick.emit(TickStatus::starting))
if (slot_connected && !signal_execute_tick().emit(TickStatus::starting))
return false;
if (!cmdex_.execute()) { // try to execute
@@ -80,11 +80,11 @@ bool CmdexSync::execute()
import_error(); // get error from cmdex and display warnings if needed
// emit this for execution loggers
cmdex_sync_signal_execute_finish().emit(CmdexSyncCommandInfo(get_command_name(),
cmdex_sync_signal_execute_finish().emit(CommandExecutorResult(get_command_name(),
get_command_args(), get_stdout_str(), get_stderr_str(), get_error_msg()));
if (slot_connected)
signal_execute_tick.emit(TickStatus::failed);
signal_execute_tick().emit(TickStatus::failed);
return false;
}
@@ -96,7 +96,7 @@ bool CmdexSync::execute()
if (!stop_requested) { // running and no stop requested yet
// call the tick function with "running" periodically.
// if it returns false, try to stop.
if (slot_connected && !signal_execute_tick.emit(TickStatus::running)) {
if (slot_connected && !signal_execute_tick().emit(TickStatus::running)) {
debug_out_info("app", DBG_FUNC_MSG << "execute_tick slot returned false, trying to stop the program.\n");
stop_requested = true;
}
@@ -119,7 +119,7 @@ bool CmdexSync::execute()
// alert the tick function
if (stop_requested && slot_connected) {
signal_execute_tick.emit(TickStatus::stopping); // ignore returned value here
signal_execute_tick().emit(TickStatus::stopping); // ignore returned value here
}
@@ -140,25 +140,88 @@ bool CmdexSync::execute()
import_error(); // get error from cmdex and display warnings if needed
// emit this for execution loggers
cmdex_sync_signal_execute_finish().emit(CmdexSyncCommandInfo(get_command_name(),
cmdex_sync_signal_execute_finish().emit(CommandExecutorResult(get_command_name(),
get_command_args(), get_stdout_str(), get_stderr_str(), get_error_msg()));
if (slot_connected)
signal_execute_tick.emit(TickStatus::stopped); // last call
signal_execute_tick().emit(TickStatus::stopped); // last call
return true;
}
void CmdexSync::set_forced_kill_timeout(std::chrono::milliseconds timeout_msec)
void CommandExecutor::set_forced_kill_timeout(std::chrono::milliseconds timeout_msec)
{
forced_kill_timeout_msec_ = timeout_msec;
}
std::string CmdexSync::get_error_msg(bool with_header) const
bool CommandExecutor::try_stop(hz::Signal sig)
{
return cmdex_.try_stop(sig);
}
bool CommandExecutor::try_kill()
{
return cmdex_.try_kill();
}
void CommandExecutor::set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::chrono::milliseconds kill_timeout_msec)
{
cmdex_.set_stop_timeouts(term_timeout_msec, kill_timeout_msec);
}
void CommandExecutor::unset_stop_timeouts()
{
cmdex_.unset_stop_timeouts();
}
bool CommandExecutor::is_running() const
{
return cmdex_.is_running();
}
void CommandExecutor::set_buffer_sizes(gsize stdout_buffer_size, gsize stderr_buffer_size)
{
cmdex_.set_buffer_sizes(stdout_buffer_size, stderr_buffer_size);
}
std::string CommandExecutor::get_stdout_str(bool clear_existing)
{
return cmdex_.get_stdout_str(clear_existing);
}
std::string CommandExecutor::get_stderr_str(bool clear_existing)
{
return cmdex_.get_stderr_str(clear_existing);
}
void CommandExecutor::set_exit_status_translator(AsyncCommandExecutor::exit_status_translator_func_t func)
{
cmdex_.set_exit_status_translator(std::move(func));
}
std::string CommandExecutor::get_error_msg(bool with_header) const
{
if (with_header)
return error_header_ + error_msg_;
@@ -167,30 +230,37 @@ std::string CmdexSync::get_error_msg(bool with_header) const
void CmdexSync::set_running_msg(const std::string& msg)
void CommandExecutor::set_running_msg(const std::string& msg)
{
running_msg_ = msg;
}
void CmdexSync::set_error_header(const std::string& msg)
void CommandExecutor::set_error_header(const std::string& msg)
{
error_header_ = msg;
}
std::string CmdexSync::get_error_header()
std::string CommandExecutor::get_error_header()
{
return error_header_;
}
void CmdexSync::import_error()
sigc::signal<bool, CommandExecutor::TickStatus>& CommandExecutor::signal_execute_tick()
{
Cmdex::error_list_t errors = cmdex_.get_errors(); // these are not clones
return signal_execute_tick_;
}
void CommandExecutor::import_error()
{
AsyncCommandExecutor::error_list_t errors = cmdex_.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
if (!errors.empty())
e = errors.back()->clone();
@@ -203,7 +273,7 @@ void CmdexSync::import_error()
void CmdexSync::on_error_warn(hz::ErrorBase* e)
void CommandExecutor::on_error_warn(hz::ErrorBase* e)
{
if (e) {
set_error_msg(e->get_message()); // this message will be displayed
@@ -212,21 +282,21 @@ void CmdexSync::on_error_warn(hz::ErrorBase* e)
void CmdexSync::set_error_msg(const std::string& error_msg)
void CommandExecutor::set_error_msg(const std::string& error_msg)
{
error_msg_ = error_msg;
}
std::string CmdexSync::get_running_msg() const
std::string CommandExecutor::get_running_msg() const
{
return running_msg_;
}
Cmdex& CmdexSync::get_command_executor()
AsyncCommandExecutor& CommandExecutor::get_async_executor()
{
return cmdex_;
}
@@ -9,8 +9,8 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef APP_CMDEX_SYNC_H
#define APP_CMDEX_SYNC_H
#ifndef COMMAND_EXECUTOR_H
#define COMMAND_EXECUTOR_H
#include <sigc++/sigc++.h>
#include <string>
@@ -20,50 +20,67 @@ Copyright:
#include "hz/error.h"
#include "hz/process_signal.h" // hz::SIGNAL_*
#include "cmdex.h"
#include "async_command_executor.h"
/// Information about a finished command.
struct CmdexSyncCommandInfo {
CmdexSyncCommandInfo(std::string c, std::string p,
std::string so, std::string se, std::string em)
: command(std::move(c)), parameters(std::move(p)), std_output(std::move(so)),
std_error(std::move(se)), error_msg(std::move(em))
struct CommandExecutorResult {
CommandExecutorResult(std::string arg_command, std::string arg_parameters,
std::string arg_std_output, std::string arg_std_error, std::string arg_error_message)
: command(std::move(arg_command)),
parameters(std::move(arg_parameters)),
std_output(std::move(arg_std_output)),
std_error(std::move(arg_std_error)),
error_message(std::move(arg_error_message))
{ }
const std::string command; ///< Executed command
const std::string parameters; ///< Command parameters
const std::string std_output; ///< Stdout data
const std::string std_error; ///< Stderr data
const std::string error_msg; ///< Execution error message
const std::string error_message; ///< Execution error message
};
/// cmdex_sync_signal_execute_finish() return signal.
using cmdex_signal_execute_finish_type = sigc::signal<void, const CmdexSyncCommandInfo&>;
using cmdex_signal_execute_finish_t = sigc::signal<void, const CommandExecutorResult&>;
/// This signal is emitted every time execute() finishes.
cmdex_signal_execute_finish_type& cmdex_sync_signal_execute_finish();
cmdex_signal_execute_finish_t& cmdex_sync_signal_execute_finish();
/// Synchronous Cmdex (command executor) with ticking support.
class CmdexSync : public sigc::trackable {
/// Synchronous AsyncCommandExecutor (command executor) with ticking support.
class CommandExecutor : public sigc::trackable {
public:
/// Constructor
CmdexSync();
CommandExecutor();
/// Constructor
CmdexSync(std::string command_name, std::string command_args);
CommandExecutor(std::string command_name, std::string command_args);
/// Deleted
CommandExecutor(const CommandExecutor& other) = delete;
/// Deleted
CommandExecutor(const CommandExecutor&& other) = delete;
/// Deleted
CommandExecutor& operator=(CommandExecutor& other) = delete;
/// Deleted
CommandExecutor& operator=(const CommandExecutor&& other) = delete;
/// Virtual destructor
virtual ~CmdexSync() = default;
virtual ~CommandExecutor() = default;
/// Set command to execute and its parameters
@@ -92,67 +109,40 @@ class CmdexSync : public sigc::trackable {
/// Try to stop the process. Call this from ticker slot while executing.
bool try_stop(hz::Signal sig = hz::Signal::Terminate)
{
return cmdex_.try_stop(sig);
}
bool try_stop(hz::Signal sig = hz::Signal::Terminate);
/// Same as try_stop(hz::SIGNAL_SIGKILL).
bool try_kill()
{
return cmdex_.try_kill();
}
bool try_kill();
/// Set a timeout (since call to this function) to terminate, kill or both (use 0 to ignore the parameter).
/// the timeouts will be unset automatically when the command exits.
/// Call from ticker slot while executing.
void set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::chrono::milliseconds kill_timeout_msec)
{
cmdex_.set_stop_timeouts(term_timeout_msec, kill_timeout_msec);
}
void set_stop_timeouts(std::chrono::milliseconds term_timeout_msec, std::chrono::milliseconds kill_timeout_msec);
/// Unset terminate / kill timeouts. This will stop the timeout counters.
/// Call from ticker slot while executing.
void unset_stop_timeouts()
{
cmdex_.unset_stop_timeouts();
}
void unset_stop_timeouts();
/// Check if the child process is running. See Cmdex::is_running().
/// Check if the child process is running. See AsyncCommandExecutor::is_running().
/// Call from ticker slot while executing.
bool is_running() const
{
return cmdex_.is_running();
}
bool is_running() const;
/// See Cmdex::set_buffer_sizes() for details. Call this before execute().
void set_buffer_sizes(gsize stdout_buffer_size = 0, gsize stderr_buffer_size = 0)
{
cmdex_.set_buffer_sizes(stdout_buffer_size, stderr_buffer_size);
}
/// See AsyncCommandExecutor::set_buffer_sizes() for details. Call this before execute().
void set_buffer_sizes(gsize stdout_buffer_size = 0, gsize stderr_buffer_size = 0);
/// See Cmdex::get_stdout_str() for details.
std::string get_stdout_str(bool clear_existing = false)
{
return cmdex_.get_stdout_str(clear_existing);
}
/// See AsyncCommandExecutor::get_stdout_str() for details.
std::string get_stdout_str(bool clear_existing = false);
/// See Cmdex::get_stderr_str() for details.
std::string get_stderr_str(bool clear_existing = false)
{
return cmdex_.get_stderr_str(clear_existing);
}
/// See AsyncCommandExecutor::get_stderr_str() for details.
std::string get_stderr_str(bool clear_existing = false);
/// See Cmdex::set_exit_status_translator() for details.
void set_exit_status_translator(Cmdex::exit_status_translator_func_t func)
{
cmdex_.set_exit_status_translator(std::move(func));
}
/// See AsyncCommandExecutor::set_exit_status_translator() for details.
void set_exit_status_translator(AsyncCommandExecutor::exit_status_translator_func_t func);
/// Get command execution error message. If \c with_header
@@ -185,9 +175,7 @@ class CmdexSync : public sigc::trackable {
};
/// This signal is emitted whenever something happens with the execution
/// (the status is changed), and periodically while the process is running.
sigc::signal<bool, TickStatus> signal_execute_tick;
sigc::signal<bool, TickStatus>& signal_execute_tick();
@@ -211,12 +199,12 @@ class CmdexSync : public sigc::trackable {
/// Get command executor object
Cmdex& get_command_executor();
AsyncCommandExecutor& get_async_executor();
private:
Cmdex cmdex_; ///< Command executor
AsyncCommandExecutor cmdex_; ///< Command executor
std::string command_name_; ///< Command name
std::string command_args_; ///< Command arguments
@@ -228,6 +216,12 @@ class CmdexSync : public sigc::trackable {
std::string error_msg_; ///< Execution error message
std::string error_header_; ///< The error message may have this prepended to it.
/// This signal is emitted whenever something happens with the execution
/// (the status is changed), and periodically while the process is running.
sigc::signal<bool, TickStatus> signal_execute_tick_;
};
+131
View File
@@ -0,0 +1,131 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#ifndef COMMAND_EXECUTOR_3WARE_H
#define COMMAND_EXECUTOR_3WARE_H
#include "local_glibmm.h"
#include "async_command_executor.h"
#include "command_executor.h"
/// Executor for tw_cli (3ware utility)
template<class ExecutorPolicy>
class TwCliExecutorGeneric : public ExecutorPolicy {
public:
/// Constructor
TwCliExecutorGeneric();
protected:
/// Exit status translate handler
static std::string translate_exit_status(int status);
/// Import the last error from command executor and clear all errors there
void import_error() override;
/// This is called when an error occurs in command executor.
/// Note: The warnings are already printed via debug_* in cmdex.
void on_error_warn(hz::ErrorBase* e) override;
};
/// tw_cli executor without GUI support
using TwCliExecutor = TwCliExecutorGeneric<CommandExecutor>;
/// tw_cli executor with GUI support
using TwCliExecutorGui = TwCliExecutorGeneric<CommandExecutorGui>;
// ------------------------------------------- Implementation
template<class ExecutorPolicy>
TwCliExecutorGeneric<ExecutorPolicy>::TwCliExecutorGeneric()
{
ExecutorPolicy::get_async_executor().set_exit_status_translator(&TwCliExecutorGeneric::translate_exit_status);
this->set_error_header(std::string(_("An error occurred while executing tw_cli:")) + "\n\n");
}
template<class ExecutorPolicy>
std::string TwCliExecutorGeneric<ExecutorPolicy>::translate_exit_status([[maybe_unused]] int status)
{
return {};
}
template<class ExecutorPolicy>
void TwCliExecutorGeneric<ExecutorPolicy>::import_error()
{
AsyncCommandExecutor& cmdex = this->get_async_executor();
AsyncCommandExecutor::error_list_t errors = cmdex.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
// find the last relevant error.
for (auto iter = errors.crbegin(); iter != errors.crend(); ++iter) {
// ignore iochannel errors, they may mask the real errors
if ((*iter)->get_type() != "giochannel" && (*iter)->get_type() != "custom") {
e = (*iter)->clone();
break;
}
}
cmdex.clear_errors(); // and clear them
if (e) { // if error is present, alert the user
on_error_warn(e);
}
}
template<class ExecutorPolicy>
void TwCliExecutorGeneric<ExecutorPolicy>::on_error_warn(hz::ErrorBase* e)
{
if (!e)
return;
// import the error only if it's relevant.
std::string error_type = e->get_type();
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
if (error_type == "giochannel" || error_type == "custom") {
return;
}
this->set_error_msg(e->get_message());
}
#endif
/// @}
+131
View File
@@ -0,0 +1,131 @@
/******************************************************************************
License: GNU General Public License v3.0 only
Copyright:
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
******************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup applib
/// \weakgroup applib
/// @{
#ifndef COMMAND_EXECUTOR_ARECA_H
#define COMMAND_EXECUTOR_ARECA_H
#include "local_glibmm.h"
#include "async_command_executor.h"
#include "command_executor.h"
/// Executor for cli (Areca utility)
template<class ExecutorPolicy>
class ArecaCliExecutorGeneric : public ExecutorPolicy {
public:
/// Constructor
ArecaCliExecutorGeneric();
protected:
/// Exit status translate handler
static std::string translate_exit_status([[maybe_unused]] [[maybe_unused]] int status);
/// Import the last error from command executor and clear all errors there
void import_error() override;
/// This is called when an error occurs in command executor.
/// Note: The warnings are already printed via debug_* in cmdex.
void on_error_warn(hz::ErrorBase* e) override;
};
/// tw_cli executor without GUI support
using ArecaCliExecutor = ArecaCliExecutorGeneric<CommandExecutor>;
/// tw_cli executor with GUI support
using ArecaCliExecutorGui = ArecaCliExecutorGeneric<CommandExecutorGui>;
// ------------------------------------------- Implementation
template<class ExecutorPolicy>
ArecaCliExecutorGeneric<ExecutorPolicy>::ArecaCliExecutorGeneric()
{
ExecutorPolicy::get_async_executor().set_exit_status_translator(&ArecaCliExecutorGeneric::translate_exit_status);
this->set_error_header(std::string(_("An error occurred while executing Areca cli:")) + "\n\n");
}
template<class ExecutorPolicy>
std::string ArecaCliExecutorGeneric<ExecutorPolicy>::translate_exit_status([[maybe_unused]] int status)
{
return std::string();
}
template<class ExecutorPolicy>
void ArecaCliExecutorGeneric<ExecutorPolicy>::import_error()
{
AsyncCommandExecutor& cmdex = this->get_async_executor();
AsyncCommandExecutor::error_list_t errors = cmdex.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
// find the last relevant error.
for (auto iter = errors.crbegin(); iter != errors.crend(); ++iter) {
// ignore iochannel errors, they may mask the real errors
if ((*iter)->get_type() != "giochannel" && (*iter)->get_type() != "custom") {
e = (*iter)->clone();
break;
}
}
cmdex.clear_errors(); // and clear them
if (e) { // if error is present, alert the user
on_error_warn(e);
}
}
template<class ExecutorPolicy>
void ArecaCliExecutorGeneric<ExecutorPolicy>::on_error_warn(hz::ErrorBase* e)
{
if (!e)
return;
// import the error only if it's relevant.
std::string error_type = e->get_type();
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
if (error_type == "giochannel" || error_type == "custom") {
return;
}
this->set_error_msg(e->get_message());
}
#endif
/// @}
@@ -10,20 +10,20 @@ Copyright:
/// @{
#include "hz/debug.h"
#include "executor_factory.h"
#include "command_executor_factory.h"
#include "smartctl_executor_gui.h"
#include "cli_executors.h"
#include "command_executor_areca.h"
#include "command_executor_3ware.h"
ExecutorFactory::ExecutorFactory(bool use_gui, Gtk::Window* parent)
CommandExecutorFactory::CommandExecutorFactory(bool use_gui, Gtk::Window* parent)
: use_gui_(use_gui), parent_(parent)
{ }
std::shared_ptr<CmdexSync> ExecutorFactory::create_executor(ExecutorFactory::ExecutorType type)
std::shared_ptr<CommandExecutor> CommandExecutorFactory::create_executor(CommandExecutorFactory::ExecutorType type)
{
switch (type) {
case ExecutorType::Smartctl:
@@ -56,7 +56,7 @@ std::shared_ptr<CmdexSync> ExecutorFactory::create_executor(ExecutorFactory::Exe
}
DBG_ASSERT(0);
return std::make_shared<CmdexSync>();
return std::make_shared<CommandExecutor>();
}
@@ -9,12 +9,12 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef EXECUTOR_FACTORY_H
#define EXECUTOR_FACTORY_H
#ifndef COMMAND_EXECUTOR_FACTORY_H
#define COMMAND_EXECUTOR_FACTORY_H
#include <memory>
#include "cmdex_sync.h"
#include "command_executor.h"
// Forward declaration
@@ -26,7 +26,7 @@ namespace Gtk {
/// This class allows you to create new executors for different commands,
/// without carrying the GUI/CLI stuff manually.
class ExecutorFactory {
class CommandExecutorFactory {
public:
/// Executor type for create_executor()
@@ -38,11 +38,11 @@ class ExecutorFactory {
/// Constructor. If \c use_gui is true, specify \c parent for the GUI dialogs.
explicit ExecutorFactory(bool use_gui, Gtk::Window* parent = nullptr);
explicit CommandExecutorFactory(bool use_gui, Gtk::Window* parent = nullptr);
/// Create a new executor instance according to \c type and the constructor parameters.
std::shared_ptr<CmdexSync> create_executor(ExecutorType type);
std::shared_ptr<CommandExecutor> create_executor(ExecutorType type);
private:
@@ -54,8 +54,8 @@ class ExecutorFactory {
/// A reference-counting pointer to ExecutorFactory
using ExecutorFactoryPtr = std::shared_ptr<ExecutorFactory>;
/// A reference-counting pointer to CommandExecutorFactory
using ExecutorFactoryPtr = std::shared_ptr<CommandExecutorFactory>;
@@ -17,16 +17,16 @@ Copyright:
#include "hz/string_algo.h"
#include "hz/fs_ns.h"
#include "cmdex_sync_gui.h"
#include "command_executor_gui.h"
bool CmdexSyncGui::execute()
bool CommandExecutorGui::execute()
{
this->create_running_dialog(); // create, but don't show.
this->set_running_dialog_abort_mode(false); // reset and set the message
return CmdexSync::execute();
return CommandExecutor::execute();
}
@@ -35,7 +35,7 @@ bool CmdexSyncGui::execute()
Gtk::MessageDialog* CmdexSyncGui::create_running_dialog(Gtk::Window* parent, const Glib::ustring& msg)
Gtk::MessageDialog* CommandExecutorGui::create_running_dialog(Gtk::Window* parent, const Glib::ustring& msg)
{
if (running_dialog_)
return running_dialog_.get();
@@ -53,7 +53,7 @@ Gtk::MessageDialog* CmdexSyncGui::create_running_dialog(Gtk::Window* parent, con
}
running_dialog_->signal_response().connect(sigc::mem_fun(*this,
&CmdexSyncGui::on_running_dialog_response));
&CommandExecutorGui::on_running_dialog_response));
running_dialog_->set_decorated(false);
running_dialog_->set_deletable(false);
@@ -70,7 +70,7 @@ Gtk::MessageDialog* CmdexSyncGui::create_running_dialog(Gtk::Window* parent, con
void CmdexSyncGui::show_hide_dialog(bool show)
void CommandExecutorGui::show_hide_dialog(bool show)
{
if (running_dialog_) {
if (show) {
@@ -88,7 +88,7 @@ void CmdexSyncGui::show_hide_dialog(bool show)
void CmdexSyncGui::update_dialog_show_timer()
void CommandExecutorGui::update_dialog_show_timer()
{
double timeout = 2.; // 2 sec for normal dialogs
if (running_dialog_abort_mode_)
@@ -110,7 +110,7 @@ void CmdexSyncGui::update_dialog_show_timer()
void CmdexSyncGui::set_running_dialog_abort_mode(bool aborting)
void CommandExecutorGui::set_running_dialog_abort_mode(bool aborting)
{
if (!running_dialog_)
return;
@@ -144,7 +144,7 @@ void CmdexSyncGui::set_running_dialog_abort_mode(bool aborting)
bool CmdexSyncGui::execute_tick_func(TickStatus status)
bool CommandExecutorGui::execute_tick_func(TickStatus status)
{
if (status == TickStatus::starting) {
if (execution_running_)
@@ -9,39 +9,39 @@ Copyright:
/// \weakgroup applib
/// @{
#ifndef APP_CMDEX_SYNC_GUI_H
#define APP_CMDEX_SYNC_GUI_H
#ifndef COMMAND_EXECUTOR_GUI_H
#define COMMAND_EXECUTOR_GUI_H
#include "local_glibmm.h"
#include <gtkmm.h>
#include <memory>
#include "cmdex_sync.h"
#include "command_executor.h"
/// Same as CmdexSync, but with GTK UI support.
/// Same as CommandExecutor, but with GTK UI support.
/// This one is noncopyable, because we can't copy the dialogs, etc...
class CmdexSyncGui : public CmdexSync {
class CommandExecutorGui : public CommandExecutor {
public:
/// Constructor
CmdexSyncGui(const std::string& cmd, const std::string& cmdargs)
: CmdexSync(cmd, cmdargs)
CommandExecutorGui(const std::string& cmd, const std::string& cmdargs)
: CommandExecutor(cmd, cmdargs)
{
signal_execute_tick.connect(sigc::mem_fun(*this, &CmdexSyncGui::execute_tick_func));
signal_execute_tick().connect(sigc::mem_fun(*this, &CommandExecutorGui::execute_tick_func));
}
/// Constructor
CmdexSyncGui()
CommandExecutorGui()
{
signal_execute_tick.connect(sigc::mem_fun(*this, &CmdexSyncGui::execute_tick_func));
signal_execute_tick().connect(sigc::mem_fun(*this, &CommandExecutorGui::execute_tick_func));
}
// Reimplemented from CmdexSync
// Reimplemented from CommandExecutor
bool execute() override;
@@ -91,7 +91,7 @@ class CmdexSyncGui : public CmdexSync {
}
/// This function is attached to CmdexSync::signal_execute_tick.
/// This function is attached to CommandExecutor::signal_execute_tick().
bool execute_tick_func(TickStatus status);
@@ -35,7 +35,7 @@ int main()
// sd.add_match_patterns(match_patterns);
sd.add_blacklist_patterns(blacklist_patterns);
auto ex_factory = std::make_shared<ExecutorFactory>(false);
auto ex_factory = std::make_shared<CommandExecutorFactory>(false);
std::string error_msg = sd.detect_and_fetch_basic_data(drives, ex_factory);
if (!error_msg.empty()) {
std::cerr << error_msg << "\n";
+7 -7
View File
@@ -112,7 +112,7 @@ bool SelfTest::is_supported() const
// start the test
std::string SelfTest::start(const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string SelfTest::start(const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (!drive_)
return "[internal error: drive must not be NULL]";
@@ -146,9 +146,9 @@ std::string SelfTest::start(const std::shared_ptr<CmdexSync>& smartctl_ex)
// update our members
// error_msg = this->update(smartctl_ex);
// if (!error_msg.empty()) // update can error out too.
// return error_msg;
// error_message = this->update(smartctl_ex);
// if (!error_message.empty()) // update can error out too.
// return error_message;
// Don't update here - the logs may not be updated this fast.
// Better to wait several seconds and then call it manually.
@@ -174,7 +174,7 @@ std::string SelfTest::start(const std::shared_ptr<CmdexSync>& smartctl_ex)
// abort test.
std::string SelfTest::force_stop(const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string SelfTest::force_stop(const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (!drive_)
return "[internal error: drive must not be NULL]";
@@ -228,7 +228,7 @@ std::string SelfTest::force_stop(const std::shared_ptr<CmdexSync>& smartctl_ex)
// update status variables. note: the returned error is an error in logic,
// not an hw defect error.
std::string SelfTest::update(const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string SelfTest::update(const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
using namespace std::literals;
@@ -236,7 +236,7 @@ std::string SelfTest::update(const std::shared_ptr<CmdexSync>& smartctl_ex)
return "[internal error: drive must not be NULL]";
std::string output;
// std::string error_msg = drive_->execute_device_smartctl("--log=selftest", smartctl_ex, output);
// std::string error_message = drive_->execute_device_smartctl("--log=selftest", smartctl_ex, output);
std::string error_msg = drive_->execute_device_smartctl("--capabilities", smartctl_ex, output);
if (!error_msg.empty()) // checks for empty output too
+4 -4
View File
@@ -19,7 +19,7 @@ Copyright:
#include <unordered_map>
#include "storage_device.h"
#include "cmdex_sync.h"
#include "command_executor.h"
@@ -98,17 +98,17 @@ class SelfTest {
/// Start the test. Note that this object is not reusable, start() must be called
/// only on newly constructed objects.
/// \return error message on error, empty string on success.
std::string start(const std::shared_ptr<CmdexSync>& smartctl_ex = nullptr);
std::string start(const std::shared_ptr<CommandExecutor>& smartctl_ex = nullptr);
/// Abort the running test.
/// \return error message on error, empty string on success.
std::string force_stop(const std::shared_ptr<CmdexSync>& smartctl_ex = nullptr);
std::string force_stop(const std::shared_ptr<CommandExecutor>& smartctl_ex = nullptr);
/// Update status variables. The user should call this every get_poll_in_seconds() seconds.
/// \return error message on error, empty string on success.
std::string update(const std::shared_ptr<CmdexSync>& smartctl_ex = nullptr);
std::string update(const std::shared_ptr<CommandExecutor>& smartctl_ex = nullptr);
private:
+1 -1
View File
@@ -70,7 +70,7 @@ hz::fs::path get_smartctl_binary()
std::string execute_smartctl(const std::string& device, const std::string& device_opts,
const std::string& command_options,
std::shared_ptr<CmdexSync> smartctl_ex, std::string& smartctl_output)
std::shared_ptr<CommandExecutor> smartctl_ex, std::string& smartctl_output)
{
#ifndef _WIN32 // win32 doesn't have slashes in devices names
{
+7 -7
View File
@@ -15,8 +15,8 @@ Copyright:
#include "local_glibmm.h"
#include <vector>
#include "cmdex.h"
#include "cmdex_sync.h"
#include "async_command_executor.h"
#include "command_executor.h"
#include "hz/fs_ns.h"
@@ -47,7 +47,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
/// Called by constructors
void construct()
{
ExecutorSync::get_command_executor().set_exit_status_translator(&SmartctlExecutorGeneric::translate_exit_status);
ExecutorSync::get_async_executor().set_exit_status_translator(&SmartctlExecutorGeneric::translate_exit_status);
this->set_error_header(std::string(_("An error occurred while executing smartctl:")) + "\n\n");
}
@@ -96,9 +96,9 @@ class SmartctlExecutorGeneric : public ExecutorSync {
/// Import the last error from command executor and clear all errors there
void import_error() override
{
Cmdex& cmdex = this->get_command_executor();
AsyncCommandExecutor& cmdex = this->get_async_executor();
Cmdex::error_list_t errors = cmdex.get_errors(); // these are not clones
AsyncCommandExecutor::error_list_t errors = cmdex.get_errors(); // these are not clones
hz::ErrorBase* e = nullptr;
// find the last relevant error.
@@ -156,7 +156,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
/// Smartctl executor without GUI support
using SmartctlExecutor = SmartctlExecutorGeneric<CmdexSync>;
using SmartctlExecutor = SmartctlExecutorGeneric<CommandExecutor>;
@@ -168,7 +168,7 @@ hz::fs::path get_smartctl_binary();
/// \return error message on error, empty string on success.
std::string execute_smartctl(const std::string& device, const std::string& device_opts,
const std::string& command_options,
std::shared_ptr<CmdexSync> smartctl_ex, std::string& smartctl_output);
std::shared_ptr<CommandExecutor> smartctl_ex, std::string& smartctl_output);
+2 -2
View File
@@ -13,12 +13,12 @@ Copyright:
#define SMARTCTL_EXECUTOR_GUI_H
#include "smartctl_executor.h"
#include "cmdex_sync_gui.h"
#include "command_executor_gui.h"
/// Smartctl executor with GUI support
using SmartctlExecutorGui = SmartctlExecutorGeneric<CmdexSyncGui>;
using SmartctlExecutorGui = SmartctlExecutorGeneric<CommandExecutorGui>;
+4 -4
View File
@@ -43,11 +43,11 @@ std::string StorageDetector::detect(std::vector<StorageDevicePtr>& drives, const
#elif defined CONFIG_KERNEL_FAMILY_WINDOWS
error_msg = detect_drives_win32(all_detected, ex_factory); // win32
error_message = detect_drives_win32(all_detected, ex_factory); // win32
#else // freebsd, etc...
error_msg = detect_drives_other(all_detected, ex_factory); // bsd, etc... . scans /dev.
error_message = detect_drives_other(all_detected, ex_factory); // bsd, etc... . scans /dev.
#endif
@@ -101,7 +101,7 @@ std::string StorageDetector::fetch_basic_data(std::vector<StorageDevicePtr>& dri
fetch_data_errors_.clear();
fetch_data_error_outputs_.clear();
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
for (auto& drive : drives) {
debug_out_info("app", "Retrieving basic information about the device...\n");
@@ -123,7 +123,7 @@ std::string StorageDetector::fetch_basic_data(std::vector<StorageDevicePtr>& dri
if (!error_msg.empty()) {
// use original executor error if present (permits matches by our users).
// if (!smartctl_ex->get_error_msg().empty())
// error_msg = smartctl_ex->get_error_msg();
// error_message = smartctl_ex->get_error_msg();
fetch_data_errors_.push_back(error_msg);
fetch_data_error_outputs_.push_back(smartctl_ex->get_stdout_str());
+2 -2
View File
@@ -16,8 +16,8 @@ Copyright:
#include <string>
#include "storage_device.h"
#include "cmdex_sync.h"
#include "executor_factory.h"
#include "command_executor.h"
#include "command_executor_factory.h"
+3 -3
View File
@@ -18,7 +18,7 @@ Copyright:
#include "local_glibmm.h" // Glib::shell_quote(), compose
#include "build_config.h"
#include "executor_factory.h"
#include "command_executor_factory.h"
#include "storage_device.h"
#include "rconfig/rconfig.h"
#include "app_pcrecpp.h"
@@ -30,7 +30,7 @@ Copyright:
/// \return error message
inline std::string execute_tw_cli(const ExecutorFactoryPtr& ex_factory, const std::string& command_options, std::string& output)
{
std::shared_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorType::TwCli);
std::shared_ptr<CommandExecutor> executor = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::TwCli);
auto binary = rconfig::get_data<std::string>("system/tw_cli_binary");
@@ -155,7 +155,7 @@ inline std::string tw_cli_get_controllers(const ExecutorFactoryPtr& ex_factory,
inline std::string smartctl_scan_drives_sequentially(const std::string& dev, const std::string& type,
int from, int to, std::vector<StorageDevicePtr>& drives, const ExecutorFactoryPtr& ex_factory, std::string& last_output)
{
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
for (int i = from; i <= to; ++i) {
std::string type_arg = hz::string_sprintf(type.c_str(), i);
+6 -6
View File
@@ -417,7 +417,7 @@ inline std::string detect_drives_linux_proc_partitions(std::vector<StorageDevice
}
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
for (const auto& device : devices) {
auto drive = std::make_shared<StorageDevice>(device);
@@ -639,7 +639,7 @@ inline std::string detect_drives_linux_adaptec(std::vector<StorageDevicePtr>& dr
return error_msg;
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
std::set<int> controller_hosts;
@@ -776,7 +776,7 @@ inline std::string detect_drives_linux_areca(std::vector<StorageDevicePtr>& driv
return error_msg;
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
for (auto& iter : controller_hosts) {
const int host_num = iter.first;
@@ -906,7 +906,7 @@ inline std::string detect_drives_linux_cciss(std::vector<StorageDevicePtr>& driv
return std::string(); // no controllers
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
for (int controller_no : controllers) {
std::string dev = std::string("/dev/cciss/c") + hz::number_to_string_nolocale(controller_no) + "d0";
@@ -985,7 +985,7 @@ inline std::string detect_drives_linux_hpsa(std::vector<StorageDevicePtr>& drive
return error_msg;
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
std::set<int> controller_hosts;
@@ -1069,7 +1069,7 @@ std::string detect_drives_linux(std::vector<StorageDevicePtr>& drives, const Exe
// For example, on Ubuntu 8.04, /dev/disk/by-id contains two device
// links for two drives, but both point to the same sdb (instead of
// sda and sdb). Plus, there are no "*-partN" files (not that we need them).
// error_msg = detect_drives_linux_udev_byid(devices); // linux udev
// error_message = detect_drives_linux_udev_byid(devices); // linux udev
error_msg = detect_drives_linux_proc_partitions(drives, ex_factory);
if (!error_msg.empty()) {
+1 -1
View File
@@ -20,7 +20,7 @@ Copyright:
#include <string>
#include <vector>
#include "executor_factory.h"
#include "command_executor_factory.h"
#include "storage_device.h"
+17 -17
View File
@@ -176,7 +176,7 @@ std::string get_scan_open_multiport_devices(std::vector<StorageDevicePtr>& drive
{
debug_out_info("app", "Getting multi-port devices through smartctl --scan-open...\n");
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
auto smartctl_binary = get_smartctl_binary();
@@ -261,7 +261,7 @@ std::string get_scan_open_multiport_devices(std::vector<StorageDevicePtr>& drive
inline std::string execute_areca_cli(const ExecutorFactoryPtr& ex_factory, const std::string& cli_binary,
const std::string& command_options, std::string& output)
{
std::shared_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorType::ArecaCli);
std::shared_ptr<CommandExecutor> executor = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::ArecaCli);
executor->set_command(Glib::shell_quote(cli_binary), command_options);
@@ -550,7 +550,7 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
}
}
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
// --- CLI mode
@@ -561,7 +561,7 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
debug_out_dump("app", "Testing Areca controller presence using smartctl...\n");
auto drive = std::make_shared<StorageDevice>("/dev/arcmsr0", "areca,1");
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
std::string error_message = drive->fetch_basic_data_and_parse(smartctl_ex);
std::string output = drive->get_info_output();
if (app_pcre_match("/No Areca controller found/mi", output)
|| app_pcre_match("/Smartctl open device: .* failed: No such device/mi", output) ) {
@@ -575,10 +575,10 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
debug_out_info("app", "Scanning Areca drives using CLI...\n");
int cli_max_controllers = 1; // TODO controller # with CLI.
for (int controller_no = 0; controller_no < cli_max_controllers; ++controller_no) {
std::string error_msg = areca_cli_get_drives(cli_binary.string(),
std::string error_message = areca_cli_get_drives(cli_binary.string(),
"/dev/arcmsr" + hz::number_to_string_nolocale(controller_no), controller_no, drives, ex_factory);
// If we get an error on controller 0, fall back to no-cli detection.
if (!error_msg.empty() && controller_no == 0) {
if (!error_message.empty() && controller_no == 0) {
use_cli = 0;
debug_out_warn("app", "Areca scan using CLI failed.\n");
if (scan_detect) {
@@ -609,9 +609,9 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
std::size_t old_drive_count = drives.size();
std::string last_output;
std::string error_msg = smartctl_scan_drives_sequentially(dev, "areca,%d", 1, max_noenc_ports, drives, ex_factory, last_output);
std::string error_message = smartctl_scan_drives_sequentially(dev, "areca,%d", 1, max_noenc_ports, drives, ex_factory, last_output);
// If the scan stopped because of no controller, stop it all.
if (!error_msg.empty() && (app_pcre_match("/No Areca controller found/mi", last_output)
if (!error_message.empty() && (app_pcre_match("/No Areca controller found/mi", last_output)
|| app_pcre_match("/Smartctl open device: .* failed: No such device/mi", last_output)) ) {
debug_out_dump("app", "Areca controller " << controller_no << " not present, stopping sequential scan.\n");
break;
@@ -623,7 +623,7 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
for (int enclosure_no = 1; enclosure_no < max_enclosures; ++enclosure_no) {
debug_out_dump("app", "Starting brute-force port scan (enclosure #" << enclosure_no << ") on 1-" << max_enc_ports << " ports, device \"" << dev
<< "\". Change the maximums by setting \"system/win32_areca_onc_max_scan_port\" and \"system/win32_areca_enc_max_enclosure\" config keys.\n");
error_msg = smartctl_scan_drives_sequentially(dev, "areca,%d/" + hz::number_to_string_nolocale(enclosure_no), 1, max_enc_ports, drives, ex_factory, last_output);
error_message = smartctl_scan_drives_sequentially(dev, "areca,%d/" + hz::number_to_string_nolocale(enclosure_no), 1, max_enc_ports, drives, ex_factory, last_output);
}
}
@@ -650,22 +650,22 @@ inline std::string detect_drives_win32_areca(std::vector<StorageDevicePtr>& driv
std::string detect_drives_win32(std::vector<StorageDevicePtr>& drives, const ExecutorFactoryPtr& ex_factory)
{
std::vector<std::string> error_msgs;
std::string error_msg;
std::string error_message;
// Construct drive letter map
debug_out_info("app", "Checking which drive corresponds to which \\\\.\\PhysicalDriveN device...\n");
std::map<char, DriveLetterInfo> drive_letter_map = win32_get_drive_letter_map();
std::shared_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorType::Smartctl);
std::shared_ptr<CommandExecutor> smartctl_ex = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::Smartctl);
// Fetch multiport devices using --scan-open.
// Note that this may return duplicates (e.g. /dev/sda and /dev/csmi0,0)
std::set<int> used_pds;
error_msg = get_scan_open_multiport_devices(drives, ex_factory, drive_letter_map, used_pds);
if (!error_msg.empty()) {
error_msgs.push_back(error_msg);
error_message = get_scan_open_multiport_devices(drives, ex_factory, drive_letter_map, used_pds);
if (!error_message.empty()) {
error_msgs.push_back(error_message);
}
bool multiport_found = !drives.empty();
@@ -782,7 +782,7 @@ std::string detect_drives_win32(std::vector<StorageDevicePtr>& drives, const Exe
if (!inst_path.empty()) {
debug_out_dump("app", "3ware 3DM2 found at\"" << inst_path << "\".\n");
std::vector<int> controllers;
error_msg = tw_cli_get_controllers(ex_factory, controllers);
error_message = tw_cli_get_controllers(ex_factory, controllers);
// ignore the error message above, it's of no use.
for (std::size_t i = 0; i < controllers.size(); ++i) {
// don't specify device, it's ignored in tw_cli mode
@@ -796,8 +796,8 @@ std::string detect_drives_win32(std::vector<StorageDevicePtr>& drives, const Exe
if (!areca_open_found) {
detect_drives_win32_areca(drives, ex_factory);
if (!error_msg.empty()) {
error_msgs.push_back(error_msg);
if (!error_message.empty()) {
error_msgs.push_back(error_message);
}
}
+5 -5
View File
@@ -99,7 +99,7 @@ void StorageDevice::clear_fetched(bool including_outputs) {
std::string StorageDevice::fetch_basic_data_and_parse(const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string StorageDevice::fetch_basic_data_and_parse(const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (this->test_is_active_)
return _("A test is currently being performed on this drive.");
@@ -254,7 +254,7 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
std::string StorageDevice::fetch_data_and_parse(const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string StorageDevice::fetch_data_and_parse(const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (this->test_is_active_)
return _("A test is currently being performed on this drive.");
@@ -346,7 +346,7 @@ StorageDevice::ParseStatus StorageDevice::get_parse_status() const
std::string StorageDevice::set_smart_enabled(bool b, const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string StorageDevice::set_smart_enabled(bool b, const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (this->test_is_active_)
return _("A test is currently being performed on this drive.");
@@ -386,7 +386,7 @@ A mandatory SMART command failed: exiting. To continue, add one or more '-T perm
std::string StorageDevice::set_aodc_enabled(bool b, const std::shared_ptr<CmdexSync>& smartctl_ex)
std::string StorageDevice::set_aodc_enabled(bool b, const std::shared_ptr<CommandExecutor>& smartctl_ex)
{
if (this->test_is_active_) {
return _("A test is currently being performed on this drive.");
@@ -809,7 +809,7 @@ std::string StorageDevice::get_device_options() const
std::string StorageDevice::execute_device_smartctl(const std::string& command_options,
const std::shared_ptr<CmdexSync>& smartctl_ex, std::string& smartctl_output, bool check_type)
const std::shared_ptr<CommandExecutor>& smartctl_ex, std::string& smartctl_output, bool check_type)
{
// don't forbid running on currently tested drive - we need to call this from the test code.
+5 -5
View File
@@ -84,14 +84,14 @@ class StorageDevice {
/// Calls "smartctl -i -H -c" (info section, health, capabilities), then parse_basic_data().
/// Called during drive detection.
/// Note: this will clear the non-basic properties!
std::string fetch_basic_data_and_parse(const std::shared_ptr<CmdexSync>& smartctl_ex = nullptr);
std::string fetch_basic_data_and_parse(const std::shared_ptr<CommandExecutor>& smartctl_ex = nullptr);
/// Detects type, smart support, smart status (on / off).
/// Note: this will clear the non-basic properties!
std::string parse_basic_data(bool do_set_properties = true, bool emit_signal = true);
/// Execute smartctl --all (all sections), get output, parse it (basic data too), fill properties.
std::string fetch_data_and_parse(const std::shared_ptr<CmdexSync>& smartctl_ex); // returns error message on error.
std::string fetch_data_and_parse(const std::shared_ptr<CommandExecutor>& smartctl_ex); // returns error message on error.
// Parses full info. If failed, try to parse it as basic info.
/// \return error message on error.
@@ -103,11 +103,11 @@ class StorageDevice {
/// Try to enable SMART.
/// \return error message on error, empty string on success
std::string set_smart_enabled(bool b, const std::shared_ptr<CmdexSync>&);
std::string set_smart_enabled(bool b, const std::shared_ptr<CommandExecutor>&);
/// Try to enable Automatic Offline Data Collection.
/// \return error message on error, empty string on success
std::string set_aodc_enabled(bool b, const std::shared_ptr<CmdexSync>&);
std::string set_aodc_enabled(bool b, const std::shared_ptr<CommandExecutor>&);
/// Get SMART status
@@ -240,7 +240,7 @@ class StorageDevice {
/// Execute smartctl on this device. Nothing is modified in this class.
/// \return error message on error, empty string on success
std::string execute_device_smartctl(const std::string& command_options,
const std::shared_ptr<CmdexSync>& smartctl_ex, std::string& output, bool check_type = false);
const std::shared_ptr<CommandExecutor>& smartctl_ex, std::string& output, bool check_type = false);
/// Emitted whenever new information is available
+6 -6
View File
@@ -103,7 +103,7 @@ GscExecutorLogWindow::GscExecutorLogWindow(BaseObjectType* gtkcobj, Glib::RefPtr
// ---------------
// Connect to CmdexSync signal
// Connect to CommandExecutor signal
cmdex_sync_signal_execute_finish().connect(sigc::mem_fun(*this,
&GscExecutorLogWindow::on_command_output_received));
@@ -148,9 +148,9 @@ void GscExecutorLogWindow::clear_view_widgets()
void GscExecutorLogWindow::on_command_output_received(const CmdexSyncCommandInfo& info)
void GscExecutorLogWindow::on_command_output_received(const CommandExecutorResult& info)
{
auto entry = std::make_shared<CmdexSyncCommandInfo>(info);
auto entry = std::make_shared<CommandExecutorResult>(info);
entries.push_back(entry);
// update tree model
@@ -189,7 +189,7 @@ void GscExecutorLogWindow::on_window_save_current_button_clicked()
return;
Gtk::TreeIter iter = selection->get_selected();
std::shared_ptr<CmdexSyncCommandInfo> entry = (*iter)[col_entry];
std::shared_ptr<CommandExecutorResult> entry = (*iter)[col_entry];
static std::string last_dir;
if (last_dir.empty()) {
@@ -305,7 +305,7 @@ void GscExecutorLogWindow::on_window_save_all_button_clicked()
exss << "\n---------------" << "STDERR" << "---------------\n";
exss << entries[i]->std_error << "\n\n";
exss << "\n---------------" << "Error Message" << "---------------\n";
exss << entries[i]->error_msg << "\n\n";
exss << entries[i]->error_message << "\n\n";
}
@@ -416,7 +416,7 @@ void GscExecutorLogWindow::on_tree_selection_changed()
Gtk::TreeIter iter = selection->get_selected();
Gtk::TreeRow row = *iter;
std::shared_ptr<CmdexSyncCommandInfo> entry = row[col_entry];
std::shared_ptr<CommandExecutorResult> entry = row[col_entry];
if (auto* output_textview = this->lookup_widget<Gtk::TextView*>("output_textview")) {
Glib::RefPtr<Gtk::TextBuffer> buffer = output_textview->get_buffer();
+4 -4
View File
@@ -18,7 +18,7 @@ Copyright:
#include <memory>
#include "applib/app_builder_widget.h"
#include "applib/cmdex_sync.h"
#include "applib/command_executor.h"
@@ -51,7 +51,7 @@ class GscExecutorLogWindow : public AppBuilderWidget<GscExecutorLogWindow, false
// -------------------- callbacks
/// Callback attached to external source, adds entries in real time.
void on_command_output_received(const CmdexSyncCommandInfo& info);
void on_command_output_received(const CommandExecutorResult& info);
@@ -82,7 +82,7 @@ class GscExecutorLogWindow : public AppBuilderWidget<GscExecutorLogWindow, false
private:
std::vector<std::shared_ptr<CmdexSyncCommandInfo>> entries; ///< Command information entries
std::vector<std::shared_ptr<CommandExecutorResult>> entries; ///< Command information entries
Glib::RefPtr<Gtk::ListStore> list_store; ///< List store
@@ -90,7 +90,7 @@ class GscExecutorLogWindow : public AppBuilderWidget<GscExecutorLogWindow, false
Gtk::TreeModelColumn<std::size_t> col_num; ///< Tree column
Gtk::TreeModelColumn<std::string> col_command; ///< Tree column
Gtk::TreeModelColumn<std::shared_ptr<CmdexSyncCommandInfo>> col_entry; ///< Tree column
Gtk::TreeModelColumn<std::shared_ptr<CommandExecutorResult>> col_entry; ///< Tree column
};
+1 -1
View File
@@ -2021,7 +2021,7 @@ void GscInfoWindow::on_test_execute_button_clicked()
// We don't use idle function here, because it has the following problem:
// CmdexSync::execute() (which is called on force_stop()) calls g_main_context_pending(),
// CommandExecutor::execute() (which is called on force_stop()) calls g_main_context_pending(),
// which returns true EVERY time, until the idle callback returns false.
// So, force_stop() exits its "execute abort" command only when the
// idle callback polls the drive on the next timeout and sees that the test
+4 -4
View File
@@ -39,7 +39,7 @@ Copyright:
#include "gsc_main_window_iconview.h"
#include "gsc_main_window.h"
#include "gsc_add_device_window.h"
#include "applib/executor_factory.h"
#include "applib/command_executor_factory.h"
#include "gsc_startup_settings.h"
@@ -1026,14 +1026,14 @@ void GscMainWindow::rescan_devices()
sd.add_blacklist_patterns(blacklist_patterns);
auto ex_factory = std::make_shared<ExecutorFactory>(true, this); // run it with GUI support
auto ex_factory = std::make_shared<CommandExecutorFactory>(true, this); // run it with GUI support
std::string error_msg = sd.detect_and_fetch_basic_data(drives_, ex_factory);
bool error = false;
// Catch permission errors.
// executor errors and outputs, not reported through error_msg.
// executor errors and outputs, not reported through error_message.
std::vector<std::string> fetch_outputs = sd.get_fetch_data_error_outputs();
for (const auto& fetch_output : fetch_outputs) {
// debug_out_error("app", DBG_FUNC_MSG << fetch_outputs[i] << "\n");
@@ -1119,7 +1119,7 @@ bool GscMainWindow::add_device(const std::string& file, const std::string& type_
drive->set_extra_arguments(extra_args);
drive->set_is_manually_added(true);
auto ex_factory = std::make_shared<ExecutorFactory>(true, this); // pass this as dialog parent
auto ex_factory = std::make_shared<CommandExecutorFactory>(true, this); // pass this as dialog parent
std::vector<StorageDevicePtr> tmp_drives;
tmp_drives.push_back(drive);