Begin b_list excel
This commit is contained in:
87
src/manage/CommandParser.cc
Normal file
87
src/manage/CommandParser.cc
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "CommandParser.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include "Colors.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace platform {
|
||||
void CommandParser::messageError(const std::string& message)
|
||||
{
|
||||
std::cout << Colors::RED() << message << Colors::RESET() << std::endl;
|
||||
}
|
||||
std::pair<char, int> CommandParser::parse(const std::string& color, const std::vector<std::tuple<std::string, char, bool>>& options, const char defaultCommand, const int maxIndex)
|
||||
{
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
std::stringstream oss;
|
||||
std::string line;
|
||||
oss << color << "Choose option (";
|
||||
bool first = true;
|
||||
for (auto& option : options) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
oss << ", ";
|
||||
}
|
||||
oss << std::get<char>(option) << "=" << std::get<std::string>(option);
|
||||
}
|
||||
oss << "): ";
|
||||
std::cout << oss.str();
|
||||
getline(std::cin, line);
|
||||
std::cout << Colors::RESET();
|
||||
line = trim(line);
|
||||
if (line.size() == 0)
|
||||
continue;
|
||||
if (all_of(line.begin(), line.end(), ::isdigit)) {
|
||||
command = defaultCommand;
|
||||
index = stoi(line);
|
||||
if (index > maxIndex || index < 0) {
|
||||
messageError("Index out of range");
|
||||
continue;
|
||||
}
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
bool found = false;
|
||||
for (auto& option : options) {
|
||||
if (line[0] == std::get<char>(option)) {
|
||||
found = true;
|
||||
// it's a match
|
||||
line.erase(line.begin());
|
||||
line = trim(line);
|
||||
if (std::get<bool>(option)) {
|
||||
// The option requires a value
|
||||
if (line.size() == 0) {
|
||||
messageError("Option " + std::get<std::string>(option) + " requires a value");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
index = stoi(line);
|
||||
if (index > maxIndex || index < 0) {
|
||||
messageError("Index out of range");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const std::invalid_argument& ia) {
|
||||
messageError("Invalid value: " + line);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (line.size() > 0) {
|
||||
messageError("option " + std::get<std::string>(option) + " doesn't accept values");
|
||||
break;
|
||||
}
|
||||
}
|
||||
command = std::get<char>(option);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
messageError("I don't know " + line);
|
||||
}
|
||||
}
|
||||
return { command, index };
|
||||
}
|
||||
} /* namespace platform */
|
20
src/manage/CommandParser.h
Normal file
20
src/manage/CommandParser.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef COMMAND_PARSER_H
|
||||
#define COMMAND_PARSER_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace platform {
|
||||
class CommandParser {
|
||||
public:
|
||||
CommandParser() = default;
|
||||
std::pair<char, int> parse(const std::string& color, const std::vector<std::tuple<std::string, char, bool>>& options, const char defaultCommand, const int maxIndex);
|
||||
char getCommand() const { return command; };
|
||||
int getIndex() const { return index; };
|
||||
private:
|
||||
void messageError(const std::string& message);
|
||||
char command;
|
||||
int index;
|
||||
};
|
||||
} /* namespace platform */
|
||||
#endif /* COMMAND_PARSER_H */
|
225
src/manage/ManageResults.cc
Normal file
225
src/manage/ManageResults.cc
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "ManageResults.h"
|
||||
#include "CommandParser.h"
|
||||
#include <filesystem>
|
||||
#include <tuple>
|
||||
#include "Colors.h"
|
||||
#include "CLocale.h"
|
||||
#include "Paths.h"
|
||||
#include "ReportConsole.h"
|
||||
#include "ReportExcel.h"
|
||||
|
||||
namespace platform {
|
||||
|
||||
ManageResults::ManageResults(int numFiles, const std::string& model, const std::string& score, bool complete, bool partial, bool compare) :
|
||||
numFiles{ numFiles }, complete{ complete }, partial{ partial }, compare{ compare }, results(Results(Paths::results(), model, score, complete, partial))
|
||||
{
|
||||
indexList = true;
|
||||
openExcel = false;
|
||||
workbook = NULL;
|
||||
if (numFiles == 0) {
|
||||
this->numFiles = results.size();
|
||||
}
|
||||
}
|
||||
void ManageResults::doMenu()
|
||||
{
|
||||
if (results.empty()) {
|
||||
std::cout << Colors::MAGENTA() << "No results found!" << Colors::RESET() << std::endl;
|
||||
return;
|
||||
}
|
||||
results.sortDate();
|
||||
list();
|
||||
menu();
|
||||
if (openExcel) {
|
||||
workbook_close(workbook);
|
||||
}
|
||||
std::cout << Colors::RESET() << "Done!" << std::endl;
|
||||
}
|
||||
void ManageResults::list()
|
||||
{
|
||||
auto temp = ConfigLocale();
|
||||
std::string suffix = numFiles != results.size() ? " of " + std::to_string(results.size()) : "";
|
||||
std::stringstream oss;
|
||||
oss << "Results on screen: " << numFiles << suffix;
|
||||
std::cout << Colors::GREEN() << oss.str() << std::endl;
|
||||
std::cout << std::string(oss.str().size(), '-') << std::endl;
|
||||
if (complete) {
|
||||
std::cout << Colors::MAGENTA() << "Only listing complete results" << std::endl;
|
||||
}
|
||||
if (partial) {
|
||||
std::cout << Colors::MAGENTA() << "Only listing partial results" << std::endl;
|
||||
}
|
||||
auto i = 0;
|
||||
int maxModel = results.maxModelSize();
|
||||
std::cout << Colors::GREEN() << " # Date " << std::setw(maxModel) << std::left << "Model" << " Score Name Score C/P Duration Title" << std::endl;
|
||||
std::cout << "=== ========== " << std::string(maxModel, '=') << " =========== =========== === ========= =============================================================" << std::endl;
|
||||
bool odd = true;
|
||||
for (auto& result : results) {
|
||||
auto color = odd ? Colors::BLUE() : Colors::CYAN();
|
||||
std::cout << color << std::setw(3) << std::fixed << std::right << i++ << " ";
|
||||
std::cout << result.to_string(maxModel) << std::endl;
|
||||
if (i == numFiles) {
|
||||
break;
|
||||
}
|
||||
odd = !odd;
|
||||
}
|
||||
}
|
||||
bool ManageResults::confirmAction(const std::string& intent, const std::string& fileName) const
|
||||
{
|
||||
std::string color;
|
||||
if (intent == "delete") {
|
||||
color = Colors::RED();
|
||||
} else {
|
||||
color = Colors::YELLOW();
|
||||
}
|
||||
std::string line;
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
std::cout << color << "Really want to " << intent << " " << fileName << "? (y/n): ";
|
||||
getline(std::cin, line);
|
||||
finished = line.size() == 1 && (tolower(line[0]) == 'y' || tolower(line[0] == 'n'));
|
||||
}
|
||||
if (tolower(line[0]) == 'y') {
|
||||
return true;
|
||||
}
|
||||
std::cout << "Not done!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
void ManageResults::report(const int index, const bool excelReport)
|
||||
{
|
||||
std::cout << Colors::YELLOW() << "Reporting " << results.at(index).getFilename() << std::endl;
|
||||
auto data = results.at(index).getJson();
|
||||
if (excelReport) {
|
||||
ReportExcel reporter(data, compare, workbook);
|
||||
reporter.show();
|
||||
openExcel = true;
|
||||
workbook = reporter.getWorkbook();
|
||||
std::cout << "Adding sheet to " << Paths::excel() + Paths::excelResults() << std::endl;
|
||||
} else {
|
||||
ReportConsole reporter(data, compare);
|
||||
reporter.show();
|
||||
}
|
||||
}
|
||||
void ManageResults::showIndex(const int index, const int idx)
|
||||
{
|
||||
// Show a dataset result inside a report
|
||||
auto data = results.at(index).getJson();
|
||||
std::cout << Colors::YELLOW() << "Showing " << results.at(index).getFilename() << std::endl;
|
||||
ReportConsole reporter(data, compare, idx);
|
||||
reporter.show();
|
||||
}
|
||||
void ManageResults::sortList()
|
||||
{
|
||||
std::cout << Colors::YELLOW() << "Choose sorting field (date='d', score='s', duration='u', model='m'): ";
|
||||
std::string line;
|
||||
char option;
|
||||
getline(std::cin, line);
|
||||
if (line.size() == 0)
|
||||
return;
|
||||
if (line.size() > 1) {
|
||||
std::cout << "Invalid option" << std::endl;
|
||||
return;
|
||||
}
|
||||
option = line[0];
|
||||
switch (option) {
|
||||
case 'd':
|
||||
results.sortDate();
|
||||
break;
|
||||
case 's':
|
||||
results.sortScore();
|
||||
break;
|
||||
case 'u':
|
||||
results.sortDuration();
|
||||
break;
|
||||
case 'm':
|
||||
results.sortModel();
|
||||
break;
|
||||
default:
|
||||
std::cout << "Invalid option" << std::endl;
|
||||
}
|
||||
}
|
||||
void ManageResults::menu()
|
||||
{
|
||||
char option;
|
||||
int index, subIndex;
|
||||
bool finished = false;
|
||||
std::string filename;
|
||||
// tuple<Option, digit, requires value>
|
||||
std::vector<std::tuple<std::string, char, bool>> mainOptions = {
|
||||
{"quit", 'q', false},
|
||||
{"list", 'l', false},
|
||||
{"delete", 'd', true},
|
||||
{"hide", 'h', true},
|
||||
{"sort", 's', false},
|
||||
{"report", 'r', true},
|
||||
{"excel", 'e', true},
|
||||
{"title", 't', true}
|
||||
};
|
||||
std::vector<std::tuple<std::string, char, bool>> listOptions = {
|
||||
{"report", 'r', true},
|
||||
{"list", 'l', false},
|
||||
{"quit", 'q', false}
|
||||
};
|
||||
auto parser = CommandParser();
|
||||
while (!finished) {
|
||||
if (indexList) {
|
||||
std::tie(option, index) = parser.parse(Colors::GREEN(), mainOptions, 'r', numFiles - 1);
|
||||
} else {
|
||||
std::tie(option, subIndex) = parser.parse(Colors::CYAN(), listOptions, 'r', results.at(index).getJson()["results"].size() - 1);
|
||||
}
|
||||
switch (option) {
|
||||
case 'q':
|
||||
finished = true;
|
||||
break;
|
||||
case 'l':
|
||||
list();
|
||||
indexList = true;
|
||||
break;
|
||||
case 'd':
|
||||
filename = results.at(index).getFilename();
|
||||
if (!confirmAction("delete", filename))
|
||||
break;
|
||||
std::cout << "Deleting " << filename << std::endl;
|
||||
results.deleteResult(index);
|
||||
std::cout << "File: " + filename + " deleted!" << std::endl;
|
||||
list();
|
||||
break;
|
||||
case 'h':
|
||||
filename = results.at(index).getFilename();
|
||||
if (!confirmAction("hide", filename))
|
||||
break;
|
||||
filename = results.at(index).getFilename();
|
||||
std::cout << "Hiding " << filename << std::endl;
|
||||
results.hideResult(index, Paths::hiddenResults());
|
||||
std::cout << "File: " + filename + " hidden! (moved to " << Paths::hiddenResults() << ")" << std::endl;
|
||||
list();
|
||||
break;
|
||||
case 's':
|
||||
sortList();
|
||||
list();
|
||||
break;
|
||||
case 'r':
|
||||
if (indexList) {
|
||||
report(index, false);
|
||||
indexList = false;
|
||||
} else {
|
||||
showIndex(index, subIndex);
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
report(index, true);
|
||||
break;
|
||||
case 't':
|
||||
std::cout << "Title: " << results.at(index).getTitle() << std::endl;
|
||||
std::cout << "New title: ";
|
||||
std::string newTitle;
|
||||
getline(std::cin, newTitle);
|
||||
if (!newTitle.empty()) {
|
||||
results.at(index).setTitle(newTitle);
|
||||
results.at(index).save();
|
||||
std::cout << "Title changed to " << newTitle << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* namespace platform */
|
31
src/manage/ManageResults.h
Normal file
31
src/manage/ManageResults.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef MANAGE_RESULTS_H
|
||||
#define MANAGE_RESULTS_H
|
||||
#include "Results.h"
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
namespace platform {
|
||||
class ManageResults {
|
||||
public:
|
||||
ManageResults(int numFiles, const std::string& model, const std::string& score, bool complete, bool partial, bool compare);
|
||||
~ManageResults() = default;
|
||||
void doMenu();
|
||||
private:
|
||||
void list();
|
||||
bool confirmAction(const std::string& intent, const std::string& fileName) const;
|
||||
void report(const int index, const bool excelReport);
|
||||
void showIndex(const int index, const int idx);
|
||||
void sortList();
|
||||
void menu();
|
||||
int numFiles;
|
||||
bool indexList;
|
||||
bool openExcel;
|
||||
bool complete;
|
||||
bool partial;
|
||||
bool compare;
|
||||
Results results;
|
||||
lxw_workbook* workbook;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MANAGE_RESULTS_H */
|
75
src/manage/Results.cc
Normal file
75
src/manage/Results.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "Results.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace platform {
|
||||
Results::Results(const std::string& path, const std::string& model, const std::string& score, bool complete, bool partial) :
|
||||
path(path), model(model), scoreName(score), complete(complete), partial(partial)
|
||||
{
|
||||
load();
|
||||
if (!files.empty()) {
|
||||
maxModel = (*max_element(files.begin(), files.end(), [](const Result& a, const Result& b) { return a.getModel().size() < b.getModel().size(); })).getModel().size();
|
||||
} else {
|
||||
maxModel = 0;
|
||||
}
|
||||
}
|
||||
void Results::load()
|
||||
{
|
||||
using std::filesystem::directory_iterator;
|
||||
for (const auto& file : directory_iterator(path)) {
|
||||
auto filename = file.path().filename().string();
|
||||
if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) {
|
||||
auto result = Result();
|
||||
result.load(path, filename);
|
||||
bool addResult = true;
|
||||
if (model != "any" && result.getModel() != model || scoreName != "any" && scoreName != result.getScoreName() || complete && !result.isComplete() || partial && result.isComplete())
|
||||
addResult = false;
|
||||
if (addResult)
|
||||
files.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Results::hideResult(int index, const std::string& pathHidden)
|
||||
{
|
||||
auto filename = files.at(index).getFilename();
|
||||
rename((path + "/" + filename).c_str(), (pathHidden + "/" + filename).c_str());
|
||||
files.erase(files.begin() + index);
|
||||
}
|
||||
void Results::deleteResult(int index)
|
||||
{
|
||||
auto filename = files.at(index).getFilename();
|
||||
remove((path + "/" + filename).c_str());
|
||||
files.erase(files.begin() + index);
|
||||
}
|
||||
int Results::size() const
|
||||
{
|
||||
return files.size();
|
||||
}
|
||||
void Results::sortDate()
|
||||
{
|
||||
sort(files.begin(), files.end(), [](const Result& a, const Result& b) {
|
||||
return a.getDate() > b.getDate();
|
||||
});
|
||||
}
|
||||
void Results::sortModel()
|
||||
{
|
||||
sort(files.begin(), files.end(), [](const Result& a, const Result& b) {
|
||||
return a.getModel() > b.getModel();
|
||||
});
|
||||
}
|
||||
void Results::sortDuration()
|
||||
{
|
||||
sort(files.begin(), files.end(), [](const Result& a, const Result& b) {
|
||||
return a.getDuration() > b.getDuration();
|
||||
});
|
||||
}
|
||||
void Results::sortScore()
|
||||
{
|
||||
sort(files.begin(), files.end(), [](const Result& a, const Result& b) {
|
||||
return a.getScore() > b.getScore();
|
||||
});
|
||||
}
|
||||
bool Results::empty() const
|
||||
{
|
||||
return files.empty();
|
||||
}
|
||||
}
|
36
src/manage/Results.h
Normal file
36
src/manage/Results.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef RESULTS_H
|
||||
#define RESULTS_H
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Result.h"
|
||||
namespace platform {
|
||||
using json = nlohmann::json;
|
||||
class Results {
|
||||
public:
|
||||
Results(const std::string& path, const std::string& model, const std::string& score, bool complete, bool partial);
|
||||
void sortDate();
|
||||
void sortScore();
|
||||
void sortModel();
|
||||
void sortDuration();
|
||||
int maxModelSize() const { return maxModel; };
|
||||
void hideResult(int index, const std::string& pathHidden);
|
||||
void deleteResult(int index);
|
||||
int size() const;
|
||||
bool empty() const;
|
||||
std::vector<Result>::iterator begin() { return files.begin(); };
|
||||
std::vector<Result>::iterator end() { return files.end(); };
|
||||
Result& at(int index) { return files.at(index); };
|
||||
private:
|
||||
std::string path;
|
||||
std::string model;
|
||||
std::string scoreName;
|
||||
bool complete;
|
||||
bool partial;
|
||||
int maxModel;
|
||||
std::vector<Result> files;
|
||||
void load(); // Loads the list of results
|
||||
};
|
||||
};
|
||||
#endif
|
49
src/manage/b_manage.cc
Normal file
49
src/manage/b_manage.cc
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <iostream>
|
||||
#include <argparse/argparse.hpp>
|
||||
#include "ManageResults.h"
|
||||
#include "config.h"
|
||||
|
||||
|
||||
void manageArguments(argparse::ArgumentParser& program, int argc, char** argv)
|
||||
{
|
||||
program.add_argument("-n", "--number").default_value(0).help("Number of results to show (0 = all)").scan<'i', int>();
|
||||
program.add_argument("-m", "--model").default_value("any").help("Filter results of the selected model)");
|
||||
program.add_argument("-s", "--score").default_value("any").help("Filter results of the score name supplied");
|
||||
program.add_argument("--complete").help("Show only results with all datasets").default_value(false).implicit_value(true);
|
||||
program.add_argument("--partial").help("Show only partial results").default_value(false).implicit_value(true);
|
||||
program.add_argument("--compare").help("Compare with best results").default_value(false).implicit_value(true);
|
||||
try {
|
||||
program.parse_args(argc, argv);
|
||||
auto number = program.get<int>("number");
|
||||
if (number < 0) {
|
||||
throw std::runtime_error("Number of results must be greater than or equal to 0");
|
||||
}
|
||||
auto model = program.get<std::string>("model");
|
||||
auto score = program.get<std::string>("score");
|
||||
auto complete = program.get<bool>("complete");
|
||||
auto partial = program.get<bool>("partial");
|
||||
auto compare = program.get<bool>("compare");
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << err.what() << std::endl;
|
||||
std::cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto program = argparse::ArgumentParser("b_manage", { project_version.begin(), project_version.end() });
|
||||
manageArguments(program, argc, argv);
|
||||
int number = program.get<int>("number");
|
||||
std::string model = program.get<std::string>("model");
|
||||
std::string score = program.get<std::string>("score");
|
||||
auto complete = program.get<bool>("complete");
|
||||
auto partial = program.get<bool>("partial");
|
||||
auto compare = program.get<bool>("compare");
|
||||
if (complete)
|
||||
partial = false;
|
||||
auto manager = platform::ManageResults(number, model, score, complete, partial, compare);
|
||||
manager.doMenu();
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user