Support saving smartctl output to text (using old text format) instead of json (#76).

This commit is contained in:
Alexander Shaduri
2025-02-15 13:22:47 +04:00
parent 9f85d09736
commit 589c280bdc
6 changed files with 106 additions and 1 deletions
+20
View File
@@ -198,6 +198,26 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonAtaParser::parse_section_info(
static const std::vector<std::tuple<std::string, std::string, PropertyRetrievalFunc>> json_keys = {
{"smartctl/output", _("Smartctl Text Output"), // the old text format
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
{
auto table_node = get_node(root_node, "smartctl/output");
if (table_node.has_value() && table_node->is_array() && !table_node.value().empty()) {
std::vector<std::string> lines;
for (const auto& entry : table_node.value()) {
lines.emplace_back(entry.get<std::string>());
}
StorageProperty p;
p.set_name(key, displayable_name);
p.value = hz::string_join(lines, "\n");
p.show_in_ui = false;
return p;
}
return hz::Unexpected(SmartctlParserError::KeyNotFound, fmt::format("Error getting key {} from JSON data.", key));
}
},
{"device/type", _("Smartctl Device Type"), // nvme, sat, etc.
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
+20
View File
@@ -75,6 +75,26 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonBasicParser::parse_section_bas
// 2. Present in devices for which we do not have specialized parsers (USB, etc.)
static const std::vector<std::tuple<std::string, std::string, PropertyRetrievalFunc>> info_keys = {
{"smartctl/output", _("Smartctl Text Output"), // the old text format
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
{
auto table_node = get_node(root_node, "smartctl/output");
if (table_node.has_value() && table_node->is_array() && !table_node.value().empty()) {
std::vector<std::string> lines;
for (const auto& entry : table_node.value()) {
lines.emplace_back(entry.get<std::string>());
}
StorageProperty p;
p.set_name(key, displayable_name);
p.value = hz::string_join(lines, "\n");
p.show_in_ui = false;
return p;
}
return hz::Unexpected(SmartctlParserError::KeyNotFound, fmt::format("Error getting key {} from JSON data.", key));
}
},
{"device/type", _("Smartctl Device Type"), // nvme, sat, etc.
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
+20
View File
@@ -114,6 +114,26 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlJsonNvmeParser::parse_section_info
static const std::vector<std::tuple<std::string, std::string, PropertyRetrievalFunc>> json_keys = {
{"smartctl/output", _("Smartctl Text Output"), // the old text format
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
{
auto table_node = get_node(root_node, "smartctl/output");
if (table_node.has_value() && table_node->is_array() && !table_node.value().empty()) {
std::vector<std::string> lines;
for (const auto& entry : table_node.value()) {
lines.emplace_back(entry.get<std::string>());
}
StorageProperty p;
p.set_name(key, displayable_name);
p.value = hz::string_join(lines, "\n");
p.show_in_ui = false;
return p;
}
return hz::Unexpected(SmartctlParserError::KeyNotFound, fmt::format("Error getting key {} from JSON data.", key));
}
},
{"device/type", _("Smartctl Device Type"), // nvme, sat, etc.
[](const nlohmann::json& root_node, const std::string& key, const std::string& displayable_name)
-> hz::ExpectedValue<StorageProperty, SmartctlParserError>
+10
View File
@@ -231,6 +231,16 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlTextAtaParser::parse(std::string_v
return hz::Unexpected(SmartctlParserError::IncompatibleVersion, "Incompatible smartctl version.");
}
// Full text output
{
StorageProperty p;
p.set_name("smartctl/output", "Smartctl Text Output");
p.reported_value = smartctl_output;
p.value = p.reported_value; // string-type value
p.show_in_ui = false;
add_property(p);
}
// sections
+10
View File
@@ -67,6 +67,16 @@ hz::ExpectedVoid<SmartctlParserError> SmartctlTextBasicParser::parse(std::string
add_property(p);
}
// Full text output
{
StorageProperty p;
p.set_name("smartctl/output", "Smartctl Text Output");
p.reported_value = output;
p.value = p.reported_value; // string-type value
p.show_in_ui = false;
add_property(p);
}
bool is_raid = false;
// Detect type. note: we can't distinguish between sata and scsi (on linux, for -d ata switch).
+26 -1
View File
@@ -848,6 +848,14 @@ void GscInfoWindow::on_save_info_button_clicked()
specific_filter->add_pattern("*.json");
specific_filter->add_pattern("*.txt");
Glib::RefPtr<Gtk::FileFilter> json_filter = Gtk::FileFilter::create();
json_filter->set_name(_("JSON Files"));
json_filter->add_pattern("*.json");
Glib::RefPtr<Gtk::FileFilter> txt_filter = Gtk::FileFilter::create();
txt_filter->set_name(_("Text Files"));
txt_filter->add_pattern("*.txt");
Glib::RefPtr<Gtk::FileFilter> all_filter = Gtk::FileFilter::create();
all_filter->set_name(_("All Files"));
all_filter->add_pattern("*");
@@ -860,6 +868,8 @@ void GscInfoWindow::on_save_info_button_clicked()
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog.get()), TRUE);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog.get()), specific_filter->gobj());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog.get()), json_filter->gobj());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog.get()), txt_filter->gobj());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog.get()), all_filter->gobj());
if (!last_dir.empty())
@@ -881,6 +891,8 @@ void GscInfoWindow::on_save_info_button_clicked()
dialog.set_do_overwrite_confirmation(true);
dialog.add_filter(specific_filter);
dialog.add_filter(json_filter);
dialog.add_filter(txt_filter);
dialog.add_filter(all_filter);
if (!last_dir.empty())
@@ -907,14 +919,27 @@ void GscInfoWindow::on_save_info_button_clicked()
#endif
rconfig::set_data("gui/drive_data_open_save_dir", last_dir);
bool txt_selected = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog.get())) == txt_filter->gobj();
if (file.extension() != ".json" && file.extension() != ".txt") {
file += ".json";
file += (txt_selected ? ".txt" : ".json");
}
bool save_txt = txt_selected || file.extension() == ".txt";
std::string data = this->drive_->get_full_output();
if (data.empty()) {
data = this->drive_->get_basic_output();
}
if (save_txt) {
if (auto p = this->drive_->get_property_repository().lookup_property("smartctl/output"); !p.empty()) {
const std::string text_output = p.get_value<std::string>();
if (!text_output.empty()) {
data = text_output;
}
}
}
const std::error_code ec = hz::fs_file_put_contents(file, data);
if (ec) {
gui_show_error_dialog(_("Cannot save SMART data to file"), ec.message(), this);