2018-10-07 03:38:44 +00:00
|
|
|
#pragma once
|
2015-05-19 07:01:18 +00:00
|
|
|
|
2015-05-20 05:22:32 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2015-09-10 20:44:25 +00:00
|
|
|
#include <list>
|
2017-12-29 07:56:31 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
2015-05-20 05:22:32 +00:00
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
#include <unistd.h>
|
2017-10-25 07:46:32 +00:00
|
|
|
#include <termios.h>
|
2017-10-30 07:29:07 +00:00
|
|
|
#else
|
|
|
|
#include <conio.h>
|
2015-07-22 19:14:50 +00:00
|
|
|
#endif
|
|
|
|
|
2016-03-04 23:02:44 +00:00
|
|
|
#include "hecl/Database.hpp"
|
|
|
|
#include "logvisor/logvisor.hpp"
|
2015-07-05 06:27:24 +00:00
|
|
|
|
2016-03-04 23:02:44 +00:00
|
|
|
extern logvisor::Module LogModule;
|
2015-07-04 06:03:59 +00:00
|
|
|
|
2018-12-08 05:18:42 +00:00
|
|
|
struct ToolPassInfo {
|
2021-06-30 18:20:45 +00:00
|
|
|
std::string pname;
|
|
|
|
std::string cwd;
|
|
|
|
std::vector<std::string> args;
|
|
|
|
std::vector<char> flags;
|
|
|
|
std::string output;
|
2018-12-08 05:18:42 +00:00
|
|
|
hecl::Database::Project* project = nullptr;
|
|
|
|
unsigned verbosityLevel = 0;
|
|
|
|
bool force = false;
|
|
|
|
bool yes = false;
|
|
|
|
bool gui = false;
|
2015-05-20 05:22:32 +00:00
|
|
|
};
|
|
|
|
|
2017-10-25 07:46:32 +00:00
|
|
|
#define RED "\033[0;31m"
|
|
|
|
#define GREEN "\033[0;32m"
|
|
|
|
#define YELLOW "\033[0;33m"
|
|
|
|
#define BLUE "\033[0;34m"
|
|
|
|
#define MAGENTA "\033[0;35m"
|
|
|
|
#define CYAN "\033[0;36m"
|
|
|
|
#define BOLD "\033[1m"
|
|
|
|
#define NORMAL "\033[0m"
|
|
|
|
|
|
|
|
#define HIDE_CURSOR "\033[?25l"
|
|
|
|
#define SHOW_CURSOR "\033[?25h"
|
|
|
|
|
|
|
|
#define WRAP_INDENT 4
|
|
|
|
|
|
|
|
extern bool XTERM_COLOR;
|
|
|
|
|
2018-12-08 05:18:42 +00:00
|
|
|
class ToolBase {
|
2015-05-19 07:01:18 +00:00
|
|
|
protected:
|
2018-12-08 05:18:42 +00:00
|
|
|
const ToolPassInfo& m_info;
|
|
|
|
bool m_good = false;
|
|
|
|
|
|
|
|
bool continuePrompt() {
|
|
|
|
if (!m_info.yes) {
|
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(FMT_STRING("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) "));
|
2018-12-08 05:18:42 +00:00
|
|
|
else
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(FMT_STRING("\nContinue? (Y/n) "));
|
2018-12-08 05:18:42 +00:00
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
int ch;
|
2017-10-25 07:46:32 +00:00
|
|
|
#ifndef _WIN32
|
2018-12-08 05:18:42 +00:00
|
|
|
struct termios tioOld, tioNew;
|
|
|
|
tcgetattr(0, &tioOld);
|
|
|
|
tioNew = tioOld;
|
|
|
|
tioNew.c_lflag &= ~ICANON;
|
|
|
|
tcsetattr(0, TCSANOW, &tioNew);
|
|
|
|
while ((ch = getchar()))
|
2017-10-25 07:46:32 +00:00
|
|
|
#else
|
2018-12-08 05:18:42 +00:00
|
|
|
while ((ch = getch()))
|
2017-10-25 07:46:32 +00:00
|
|
|
#endif
|
2018-12-08 05:18:42 +00:00
|
|
|
{
|
|
|
|
if (ch == 'n' || ch == 'N') {
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(FMT_STRING("\n"));
|
2018-12-08 05:18:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (ch == 'y' || ch == 'Y' || ch == '\r' || ch == '\n')
|
|
|
|
break;
|
|
|
|
}
|
2017-10-25 07:46:32 +00:00
|
|
|
#ifndef _WIN32
|
2018-12-08 05:18:42 +00:00
|
|
|
tcsetattr(0, TCSANOW, &tioOld);
|
2017-10-25 07:46:32 +00:00
|
|
|
#endif
|
|
|
|
}
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(FMT_STRING("\n"));
|
2018-12-08 05:18:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2017-10-25 07:46:32 +00:00
|
|
|
|
2015-05-19 07:01:18 +00:00
|
|
|
public:
|
2019-08-20 02:49:24 +00:00
|
|
|
explicit ToolBase(const ToolPassInfo& info) : m_info(info) {
|
2018-12-08 05:18:42 +00:00
|
|
|
hecl::VerbosityLevel = info.verbosityLevel;
|
|
|
|
hecl::GuiMode = info.gui;
|
|
|
|
}
|
|
|
|
virtual ~ToolBase() = default;
|
2021-06-30 18:20:45 +00:00
|
|
|
virtual std::string_view toolName() const = 0;
|
2018-12-08 05:18:42 +00:00
|
|
|
virtual int run() = 0;
|
|
|
|
virtual void cancel() {}
|
2019-08-20 02:35:30 +00:00
|
|
|
explicit operator bool() const { return m_good; }
|
2015-05-19 07:01:18 +00:00
|
|
|
};
|
|
|
|
|
2018-12-08 05:18:42 +00:00
|
|
|
class HelpOutput {
|
2015-05-26 04:42:20 +00:00
|
|
|
public:
|
2019-08-20 02:51:04 +00:00
|
|
|
using HelpFunc = void (*)(HelpOutput&);
|
2015-05-26 04:42:20 +00:00
|
|
|
|
2018-12-08 05:18:42 +00:00
|
|
|
private:
|
2019-08-20 02:52:33 +00:00
|
|
|
FILE* m_sout = nullptr;
|
2018-12-08 05:18:42 +00:00
|
|
|
HelpFunc m_helpFunc;
|
|
|
|
int m_lineWidth;
|
2021-06-30 18:20:45 +00:00
|
|
|
std::string m_wrapBuffer;
|
2018-12-08 05:18:42 +00:00
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void _wrapBuf(std::string& string) {
|
2018-12-08 05:18:42 +00:00
|
|
|
int counter;
|
2021-06-30 18:20:45 +00:00
|
|
|
std::string::iterator it = string.begin();
|
2018-12-08 05:18:42 +00:00
|
|
|
|
|
|
|
while (it != string.end()) {
|
|
|
|
std::ptrdiff_t v = it - string.begin();
|
|
|
|
|
|
|
|
/* copy string until the end of the line is reached */
|
|
|
|
for (counter = WRAP_INDENT; counter < m_lineWidth; ++counter) {
|
|
|
|
if (it >= string.end())
|
|
|
|
return;
|
2021-06-30 18:20:45 +00:00
|
|
|
if (*it == '\n') {
|
2018-12-08 05:18:42 +00:00
|
|
|
counter = WRAP_INDENT;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
if (counter == WRAP_INDENT) {
|
|
|
|
for (int i = 0; i < WRAP_INDENT; ++i)
|
2021-06-30 18:20:45 +00:00
|
|
|
it = string.insert(it, ' ') + 1;
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
|
|
|
if (it >= string.end())
|
|
|
|
return;
|
2021-06-30 18:20:45 +00:00
|
|
|
if (*it != '\n')
|
2018-12-08 05:18:42 +00:00
|
|
|
++it;
|
|
|
|
}
|
|
|
|
/* check for whitespace */
|
|
|
|
if (isspace(*it)) {
|
2021-06-30 18:20:45 +00:00
|
|
|
*it = '\n';
|
2018-12-08 05:18:42 +00:00
|
|
|
counter = WRAP_INDENT;
|
|
|
|
++it;
|
|
|
|
} else {
|
|
|
|
/* check for nearest whitespace back in string */
|
2021-06-30 18:20:45 +00:00
|
|
|
for (std::string::iterator k = it; k != string.begin(); --k) {
|
2018-12-08 05:18:42 +00:00
|
|
|
if (isspace(*k)) {
|
|
|
|
counter = WRAP_INDENT;
|
|
|
|
if (k - string.begin() < v)
|
2021-06-30 18:20:45 +00:00
|
|
|
k = string.insert(it, '\n');
|
2015-05-26 04:42:20 +00:00
|
|
|
else
|
2021-06-30 18:20:45 +00:00
|
|
|
*k = '\n';
|
2018-12-08 05:18:42 +00:00
|
|
|
it = k + 1;
|
|
|
|
break;
|
|
|
|
}
|
2015-05-26 04:42:20 +00:00
|
|
|
}
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
2015-05-26 04:42:20 +00:00
|
|
|
}
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
2015-05-26 04:42:20 +00:00
|
|
|
|
|
|
|
public:
|
2019-08-20 02:49:24 +00:00
|
|
|
explicit HelpOutput(HelpFunc helpFunc)
|
2019-08-20 02:52:33 +00:00
|
|
|
: m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {}
|
2015-05-26 04:42:20 +00:00
|
|
|
|
2018-12-08 05:18:42 +00:00
|
|
|
void go() {
|
2015-06-10 02:40:03 +00:00
|
|
|
#if _WIN32
|
2018-12-08 05:18:42 +00:00
|
|
|
m_sout = stdout;
|
|
|
|
m_helpFunc(*this);
|
2015-06-10 02:40:03 +00:00
|
|
|
#else
|
2018-12-08 05:18:42 +00:00
|
|
|
m_sout = popen("less -R", "w");
|
|
|
|
if (m_sout) {
|
|
|
|
m_helpFunc(*this);
|
|
|
|
pclose(m_sout);
|
|
|
|
} else {
|
|
|
|
m_sout = stdout;
|
|
|
|
m_helpFunc(*this);
|
2015-05-26 04:42:20 +00:00
|
|
|
}
|
2018-12-08 05:18:42 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void print(const char* str) { fmt::print(m_sout, FMT_STRING("{}"), str); }
|
2018-12-08 05:18:42 +00:00
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void printBold(const char* str) {
|
2018-12-08 05:18:42 +00:00
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL ""), str);
|
2018-12-08 05:18:42 +00:00
|
|
|
else
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("{}"), str);
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void secHead(const char* headName) {
|
2018-12-08 05:18:42 +00:00
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL "\n"), headName);
|
2018-12-08 05:18:42 +00:00
|
|
|
else
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("{}\n"), headName);
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void optionHead(const char* flag, const char* synopsis) {
|
2018-12-08 05:18:42 +00:00
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL " ({})\n"), flag, synopsis);
|
2018-12-08 05:18:42 +00:00
|
|
|
else
|
2021-06-30 18:20:45 +00:00
|
|
|
fmt::print(m_sout, FMT_STRING("{} ({})\n"), flag, synopsis);
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void beginWrap() { m_wrapBuffer.clear(); }
|
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void wrap(const char* str) { m_wrapBuffer += str; }
|
2018-12-08 05:18:42 +00:00
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
void wrapBold(const char* str) {
|
2018-12-08 05:18:42 +00:00
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
m_wrapBuffer += "" BOLD "";
|
2018-12-08 05:18:42 +00:00
|
|
|
m_wrapBuffer += str;
|
|
|
|
if (XTERM_COLOR)
|
2021-06-30 18:20:45 +00:00
|
|
|
m_wrapBuffer += "" NORMAL "";
|
2018-12-08 05:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void endWrap() {
|
|
|
|
_wrapBuf(m_wrapBuffer);
|
2021-06-30 18:20:45 +00:00
|
|
|
m_wrapBuffer += '\n';
|
|
|
|
fmt::print(m_sout, FMT_STRING("{}"), m_wrapBuffer);
|
2018-12-08 05:18:42 +00:00
|
|
|
m_wrapBuffer.clear();
|
|
|
|
}
|
2015-05-26 04:42:20 +00:00
|
|
|
};
|
|
|
|
|
2021-06-30 18:20:45 +00:00
|
|
|
static std::string MakePathArgAbsolute(const std::string& arg, const std::string& cwd) {
|
2015-10-02 04:06:45 +00:00
|
|
|
#if _WIN32
|
2021-06-30 18:20:45 +00:00
|
|
|
if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == ':')
|
2018-12-08 05:18:42 +00:00
|
|
|
return arg;
|
2021-06-30 18:20:45 +00:00
|
|
|
if (arg[0] == '\\' || arg[0] == '/')
|
2018-12-08 05:18:42 +00:00
|
|
|
return arg;
|
2021-06-30 18:20:45 +00:00
|
|
|
return cwd + '\\' + arg;
|
2015-10-02 04:06:45 +00:00
|
|
|
#else
|
2021-06-30 18:20:45 +00:00
|
|
|
if (arg[0] == '/' || arg[0] == '\\')
|
2018-12-08 05:18:42 +00:00
|
|
|
return arg;
|
2021-06-30 18:20:45 +00:00
|
|
|
if (cwd.back() == '/' || cwd.back() == '\\')
|
2018-12-08 05:18:42 +00:00
|
|
|
return cwd + arg;
|
2021-06-30 18:20:45 +00:00
|
|
|
return cwd + '/' + arg;
|
2015-10-02 04:06:45 +00:00
|
|
|
#endif
|
|
|
|
}
|