304 lines
9.7 KiB
C++
304 lines
9.7 KiB
C++
|
|
#include <cstdlib>
|
||
|
|
#include <fstream>
|
||
|
|
# include <iostream>
|
||
|
|
# include <filesystem>
|
||
|
|
# include <unordered_map>
|
||
|
|
|
||
|
|
#include <QObject>
|
||
|
|
#include <QJsonDocument>
|
||
|
|
#include <QJsonObject>
|
||
|
|
#include <QJsonArray>
|
||
|
|
#include <QString>
|
||
|
|
#include <QCoreApplication>
|
||
|
|
#include <QProcess>
|
||
|
|
#include <QFile>
|
||
|
|
#include <QTimer>
|
||
|
|
# include <QStandardPaths>
|
||
|
|
#include <sstream>
|
||
|
|
#include <type_traits>
|
||
|
|
# include <unistd.h>
|
||
|
|
#include <unordered_map>
|
||
|
|
# include <expected>
|
||
|
|
|
||
|
|
namespace globals {
|
||
|
|
static std::filesystem::path config_path;
|
||
|
|
|
||
|
|
std::expected<QJsonObject, bool> read_config() {
|
||
|
|
if (std::filesystem::exists(globals::config_path)) {
|
||
|
|
std::fstream file_input(globals::config_path, std::fstream::in);
|
||
|
|
std::string data;
|
||
|
|
std::string temp;
|
||
|
|
while(std::getline(file_input, temp)) {
|
||
|
|
data += temp;
|
||
|
|
}
|
||
|
|
file_input.close();
|
||
|
|
return QJsonDocument::fromJson(QByteArray::fromStdString(data)).object();
|
||
|
|
} else {
|
||
|
|
return std::unexpected(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void overwrite_config(QJsonObject& obj) {
|
||
|
|
QJsonDocument doc;
|
||
|
|
doc.setObject(obj);
|
||
|
|
std::string data = doc.toJson().toStdString();
|
||
|
|
std::fstream file_input(globals::config_path, std::fstream::out);
|
||
|
|
file_input << data;
|
||
|
|
file_input.flush();
|
||
|
|
file_input.close();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string get_current_time() {
|
||
|
|
const auto now = std::chrono::system_clock::now();
|
||
|
|
std::time_t ctime_now = std::chrono::system_clock::to_time_t(now);
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << "[" << std::put_time(std::localtime(&ctime_now), "%d-%m-%y %H:%M:%S") << "] ";
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
int get_parent_id() {
|
||
|
|
std::stringstream ss;
|
||
|
|
int var;
|
||
|
|
ss << getppid();
|
||
|
|
ss >> var;
|
||
|
|
return var;
|
||
|
|
}
|
||
|
|
|
||
|
|
void show_help() {
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << "Usage: goto [OPTION|LINK_NAME]" << std::endl;
|
||
|
|
ss << "Options:" << std::endl;
|
||
|
|
ss << " -h --help : Show this info" << std::endl;
|
||
|
|
ss << " -c --create_link : Create a new link e.g: goto --create_link [LINK_NAME] [FROM_PATH]" << std::endl;
|
||
|
|
ss << " -l --list : List all the existing links" << std::endl;
|
||
|
|
ss << " -d --delete_link : Delete an exisiting link e.g: goto -d [LINK_NAME]" << std::endl;
|
||
|
|
ss << " -rf --delete_file : Delete the existing link file completely." << std::endl;
|
||
|
|
ss << " [LINK_NAME] : Goes to an exisiting link e.g: goto [LINK_NAME]" << std::endl;
|
||
|
|
ss << " [LINK_NAME] : Rules for creating [LINK_NAME] name must be BASH variable and must not start with \"-\"" << std::endl;
|
||
|
|
ss << " [LINK_NAME] : [LINK_NAME] cannot be \"last\"" << std::endl;
|
||
|
|
std::cout << ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
void show_invalid() {
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << "[goto] Invalid arguments use -h or --help for help" << std::endl;
|
||
|
|
std::cout << ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void print_links() {
|
||
|
|
QJsonObject links = globals::read_config().or_else([](bool err){
|
||
|
|
std::cout << "Could not read config file." << std::endl;
|
||
|
|
exit(-1);
|
||
|
|
return std::expected<QJsonObject, bool> {QJsonObject()};
|
||
|
|
}).value();
|
||
|
|
std::unordered_map<std::string, std::string> link_list;
|
||
|
|
for(auto i = links.begin(); i != links.end(); i++) {
|
||
|
|
link_list[i.key().toStdString()] = i.value().toString().toStdString();
|
||
|
|
}
|
||
|
|
int iter = 1;
|
||
|
|
std::cout << "Links from file: " << globals::config_path << std::endl;
|
||
|
|
for(auto &[key, value]: link_list) {
|
||
|
|
if(key != "last")
|
||
|
|
std::cout << iter++ << ". " << key << " --> " << value << std::endl;
|
||
|
|
}
|
||
|
|
if(link_list.find("last") != link_list.end()) {
|
||
|
|
std::cout << iter << ". Last place --> " << link_list["last"] << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void delete_link(std::string link_name) {
|
||
|
|
QJsonObject obj = globals::read_config().or_else([](bool err){
|
||
|
|
std::cout << "Could not read config file." << std::endl;
|
||
|
|
exit(-1);
|
||
|
|
return std::expected<QJsonObject, bool> {QJsonObject()};
|
||
|
|
}).value();
|
||
|
|
obj.remove(QString::fromStdString(link_name));
|
||
|
|
globals::overwrite_config(obj);
|
||
|
|
std::cout << "Link: " << link_name << " deleted." << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
void create_link(std::string link_name, std::string dir) {
|
||
|
|
if(dir == ".") {
|
||
|
|
dir = std::filesystem::current_path().string();
|
||
|
|
}
|
||
|
|
if(std::filesystem::exists(globals::config_path)) {
|
||
|
|
QJsonObject links = globals::read_config().or_else([](bool err){
|
||
|
|
std::cout << "Could not read config file." << std::endl;
|
||
|
|
exit(-1);
|
||
|
|
return std::expected<QJsonObject, bool> {QJsonObject()};
|
||
|
|
}).value();
|
||
|
|
if(links.find(QString::fromStdString(link_name)) == links.end())
|
||
|
|
links[QString::fromStdString(link_name)] = QString::fromStdString(dir);
|
||
|
|
else {
|
||
|
|
std::string char_in;
|
||
|
|
std::cout << "Warning: Link name: " << link_name << " already exists. Do you want to overwrite it?";
|
||
|
|
std::cout.flush();
|
||
|
|
std::getline(std::cin, char_in);
|
||
|
|
if(char_in.size() >= 1 && (char_in[0] == 'Y' || char_in[0] == 'y')) {
|
||
|
|
std::string prev_value = links[QString::fromStdString(link_name)].toString().toStdString();
|
||
|
|
links[QString::fromStdString(link_name)] = QString::fromStdString(dir);
|
||
|
|
globals::overwrite_config(links);
|
||
|
|
std::cout << "Overwritten link: " << link_name << " -> " << dir << " from: " << prev_value << " in: " << globals::config_path << std::endl;
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
globals::overwrite_config(links);
|
||
|
|
std::cout << "Written new link: " << link_name << " -> " << dir << " in: " << globals::config_path << std::endl;
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
QJsonObject new_link;
|
||
|
|
new_link[QString::fromStdString(link_name)] = QString::fromStdString(dir);
|
||
|
|
globals::overwrite_config(new_link);
|
||
|
|
std::cout << "Written new link: " << link_name << " -> " << dir << " in: " << globals::config_path << std::endl;
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void goto_link(std::string link_name) {
|
||
|
|
QJsonObject config = globals::read_config().or_else([](bool err){
|
||
|
|
std::cout << "Could not read config file." << std::endl;
|
||
|
|
exit(-1);
|
||
|
|
return std::expected<QJsonObject, bool> {QJsonObject()};
|
||
|
|
}).value();
|
||
|
|
std::string place = config[QString::fromStdString(link_name)].toString("-_- Place Does not exist.").toStdString();
|
||
|
|
if(place == "-_- Place Does not exist.") {
|
||
|
|
std::cout << "Specified link: " << link_name << " does not exist in links file." << std::endl;
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
config["last"] = QString::fromStdString(place);
|
||
|
|
globals::overwrite_config(config);
|
||
|
|
// int parent_id = get_parent_id();
|
||
|
|
// std::ostringstream std_out, std_err, std_log;
|
||
|
|
//
|
||
|
|
// auto prev_cout_buffer = std::cout.rdbuf();
|
||
|
|
// auto prev_clog_buffer = std::clog.rdbuf();
|
||
|
|
// auto prev_cerr_buffer = std::cerr.rdbuf();
|
||
|
|
|
||
|
|
// std::cout.rdbuf(std_out.rdbuf());
|
||
|
|
// std::cerr.rdbuf(std_err.rdbuf());
|
||
|
|
// std::clog.rdbuf(std_log.rdbuf());
|
||
|
|
|
||
|
|
std::cout << place << std::endl;
|
||
|
|
// system(std::format("sh -c cd {}", place).c_str());
|
||
|
|
// system(std::format("kill -9 {}", parent_id).c_str());
|
||
|
|
// QProcess *proc = new QProcess();
|
||
|
|
// proc->setProgram("/usr/bin/bash");
|
||
|
|
// proc->setWorkingDirectory(QString::fromStdString(place));
|
||
|
|
// proc->startDetached();
|
||
|
|
|
||
|
|
// std::cout.rdbuf(prev_cout_buffer);
|
||
|
|
// std::cerr.rdbuf(prev_cerr_buffer);
|
||
|
|
// std::clog.rdbuf(prev_clog_buffer);
|
||
|
|
}
|
||
|
|
|
||
|
|
void delete_file() {
|
||
|
|
std::string in;
|
||
|
|
std::cout << "Are you sure you want to completely remove the links.json file?";
|
||
|
|
std::cout.flush();
|
||
|
|
std::getline(std::cin, in);
|
||
|
|
if(in.size() >= 1 && (in[0] == 'y' || in[0] == 'Y')) {
|
||
|
|
std::filesystem::remove(globals::config_path);
|
||
|
|
std::cout << "Removed config file from: " <<globals::config_path << std::endl;
|
||
|
|
} else {
|
||
|
|
std::cout << "Not removing config file." << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(int argc, char *argv[]) {
|
||
|
|
QCoreApplication app(argc, argv);
|
||
|
|
QCoreApplication::setApplicationName("goto");
|
||
|
|
QCoreApplication::setApplicationVersion("0.0.1");
|
||
|
|
globals::config_path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).toStdString();
|
||
|
|
globals::config_path = globals::config_path / "goto";
|
||
|
|
if(!std::filesystem::exists(globals::config_path)) {
|
||
|
|
std::filesystem::create_directories(globals::config_path);
|
||
|
|
}
|
||
|
|
globals::config_path = globals::config_path / "links.json";
|
||
|
|
|
||
|
|
std::unordered_map<std::string, int> command_list = {{"help", 1}, {"h", 1}, {"create_link", 2}, {"c", 2}, {"l", 3}, {"list", 3}, {"d", 4}, {"delete_link", 4}, {"rf", 5}, {"delete_file", 5}};
|
||
|
|
|
||
|
|
|
||
|
|
int command_size = argc - 1;
|
||
|
|
if(command_size == 0) {
|
||
|
|
show_invalid();
|
||
|
|
exit(0);
|
||
|
|
} else {
|
||
|
|
bool arg = false;
|
||
|
|
if(std::string(argv[1]).starts_with("--") || std::string(argv[1]).starts_with("-")) {
|
||
|
|
while(argv[1][0] == '-') {
|
||
|
|
++argv[1];
|
||
|
|
}
|
||
|
|
arg = true;
|
||
|
|
}
|
||
|
|
if(arg) {
|
||
|
|
if(command_list.find(argv[1]) == command_list.end()) {
|
||
|
|
show_invalid();
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
switch (command_list[argv[1]]) {
|
||
|
|
case 1: {
|
||
|
|
show_help();
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
case 2: {
|
||
|
|
if(command_size != 3) {
|
||
|
|
show_invalid();
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
std::string link_name, directory;
|
||
|
|
link_name = argv[2];
|
||
|
|
directory = argv[3];
|
||
|
|
create_link(link_name, directory);
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
case 3: {
|
||
|
|
if(command_size != 1) {
|
||
|
|
show_invalid();
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
print_links();
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
case 4: {
|
||
|
|
if(command_size != 2) {
|
||
|
|
show_invalid();
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
std::string link_name;
|
||
|
|
link_name = argv[2];
|
||
|
|
delete_link(link_name);
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
case 5: {
|
||
|
|
if(command_size != 1) {
|
||
|
|
show_invalid();
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
delete_file();
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
std::string link_name = argv[1];
|
||
|
|
goto_link(link_name);
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
return app.exec();
|
||
|
|
}
|
||
|
|
|