parent
b9e9119832
commit
e35536c7e3
@ -0,0 +1,130 @@ |
||||
#include "builder.hpp" |
||||
#include "dbc.hpp" |
||||
#include "watcher.hpp" |
||||
#include "game_engine.hpp" |
||||
#include <chrono> // for milliseconds |
||||
#include <efsw/efsw.hpp> |
||||
#include <fmt/chrono.h> |
||||
#include <fmt/color.h> |
||||
#include <fmt/core.h> |
||||
#include <fmt/core.h> |
||||
#include <fstream> |
||||
#include <git2.h> |
||||
#include <iostream> |
||||
#include <memory> // for allocator, shared_ptr |
||||
#include <regex> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> // for EXIT_SUCCESS |
||||
#include <string> // for operator+, to_string |
||||
#include <thread> // for sleep_for |
||||
#include <unistd.h> |
||||
#include <vector> |
||||
|
||||
using namespace std; |
||||
using namespace fmt; |
||||
|
||||
#define BUF_MAX 1024 |
||||
|
||||
void Builder::run_build(GameEngine &game, const char* command) { |
||||
regex err_re("(.*?):([0-9]+):([0-9]+):\\s*(.*?):\\s*(.*)\n*"); |
||||
|
||||
char buffer[BUF_MAX]; // BUF_MAX is a define already?
|
||||
ofstream stats_out; |
||||
stats_out.open("stats.csv", ios::out | ios::app); |
||||
std::time_t tstamp = std::time(nullptr); |
||||
|
||||
dbc::check(stats_out.good(), "Error opening stats.csv file."); |
||||
dbc::pre("simple test", [&]() { return stats_out.good(); }); |
||||
|
||||
// need to catch the error message when the command is bad
|
||||
FILE *build_out = popen(command, "r"); |
||||
dbc::check(build_out != nullptr, "Failed to run command."); |
||||
|
||||
int hit_count = 0; |
||||
|
||||
while(fgets(buffer, BUF_MAX, build_out) != nullptr) { |
||||
string line(buffer); // yeah, that's probably a problem
|
||||
|
||||
smatch err; |
||||
bool match = regex_match(line, err, err_re); |
||||
|
||||
if(match) { |
||||
string file_name = err[1].str(); |
||||
string lnumber = err[2].str(); |
||||
string col = err[3].str(); |
||||
string type = err[4].str(); |
||||
string message = err[5].str(); |
||||
|
||||
string result = format("{:%FT%T},{},{},{},{},{}\n", |
||||
fmt::localtime(tstamp), file_name, |
||||
lnumber, col, type, message); |
||||
|
||||
stats_out << result; |
||||
gui.output(format("\nHIT WITH {} @ {}:{}:{} {}", type, file_name, lnumber, col, message)); |
||||
|
||||
game.hit(type); |
||||
++hit_count; |
||||
|
||||
// refactor this
|
||||
if(game.is_dead()) { |
||||
gui.output(format("YOU DIED!\n")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if(hit_count == 0) { |
||||
game.heal(10); |
||||
} |
||||
|
||||
int rc = pclose(build_out); |
||||
if(rc == 0) { |
||||
gui.output("BUILD FINISHED!"); |
||||
} else { |
||||
gui.output(format("!!! BUILD FAILED. Your command correct? '{}'", command)); |
||||
} |
||||
|
||||
stats_out.close(); |
||||
dbc::post("a post test", [&]() { return !stats_out.is_open(); }); |
||||
} |
||||
|
||||
void Builder::run(const char *git_path, const char *build_cmd) { |
||||
git_repository* repo = nullptr; |
||||
|
||||
try { |
||||
gui.output(format("Using build command: {}", build_cmd)); |
||||
efsw::FileWatcher* fileWatcher = new efsw::FileWatcher(); |
||||
dbc::check(fileWatcher != nullptr, "Failed to create filewatcher."); |
||||
|
||||
git_libgit2_init(); |
||||
|
||||
int err = git_repository_open(&repo, git_path); |
||||
dbc::check(err == 0, git_error_last()->message); |
||||
|
||||
UpdateListener* listener = new UpdateListener(repo); |
||||
dbc::check(listener != nullptr, "Failed to create listener."); |
||||
|
||||
gui.output(format("Watching directory {} for changes...\n", git_path)); |
||||
efsw::WatchID wid = fileWatcher->addWatch(git_path, listener, true); |
||||
|
||||
int rc = gui.main_loop(game, [&] { |
||||
fileWatcher->watch(); |
||||
|
||||
if(listener->changes) { |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||
gui.output(format("CHANGES! Running build {}", build_cmd)); |
||||
run_build(game, build_cmd); |
||||
listener->reset_state(); |
||||
} |
||||
return 0; |
||||
}); |
||||
|
||||
dbc::check(rc == 0, "Invalid return from main_loop."); |
||||
|
||||
fileWatcher->removeWatch(wid); |
||||
git_libgit2_shutdown(); |
||||
} catch(dbc::Error &err) { |
||||
if(repo != nullptr) git_repository_free(repo); |
||||
git_libgit2_shutdown(); |
||||
throw err; |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
#pragma once |
||||
#include "gui.hpp" |
||||
#include "game_engine.hpp" |
||||
|
||||
class Builder { |
||||
GUI gui; |
||||
GameEngine game; |
||||
|
||||
public: |
||||
|
||||
Builder(GUI &g, GameEngine &engine) : gui(g), game(engine) {}; |
||||
|
||||
void run_build(GameEngine &game, const char* command); |
||||
|
||||
void run(const char *git_path, const char *build_cmd); |
||||
|
||||
}; |
@ -1,176 +1,21 @@ |
||||
#include "dbc.hpp" |
||||
#include "gui.hpp" |
||||
#include "game_engine.hpp" |
||||
#include <chrono> // for milliseconds |
||||
#include <efsw/efsw.hpp> |
||||
#include <filesystem> |
||||
#include <fmt/chrono.h> |
||||
#include <fmt/color.h> |
||||
#include "builder.hpp" |
||||
#include <fmt/core.h> |
||||
#include <fmt/core.h> |
||||
#include <fstream> |
||||
#include <ftxui/component/event.hpp> // for Event |
||||
#include <ftxui/component/mouse.hpp> // for ftxui |
||||
#include <ftxui/dom/elements.hpp> // for text, separator, Element, operator|, vbox, border |
||||
#include <git2.h> |
||||
#include <iostream> |
||||
#include <memory> // for allocator, shared_ptr |
||||
#include <regex> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> // for EXIT_SUCCESS |
||||
#include <string> // for operator+, to_string |
||||
#include <thread> // for sleep_for |
||||
#include <unistd.h> |
||||
#include <vector> |
||||
|
||||
#include "ftxui/component/component.hpp" // for CatchEvent, Renderer, operator|= |
||||
#include "ftxui/component/loop.hpp" // for Loop |
||||
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive |
||||
|
||||
using namespace ftxui; |
||||
using namespace std; |
||||
|
||||
using namespace std; |
||||
using namespace fmt; |
||||
namespace fs = std::filesystem; |
||||
|
||||
const auto ERROR = fmt::emphasis::bold | fg(fmt::color::red); |
||||
|
||||
#define BUF_MAX 1024 |
||||
|
||||
class UpdateListener : public efsw::FileWatchListener { |
||||
public: |
||||
bool changes = false; |
||||
git_repository* repo = nullptr; |
||||
|
||||
UpdateListener(git_repository *r) : repo(r) {}; |
||||
|
||||
void handleFileAction(efsw::WatchID watchid, |
||||
const std::string& dir, |
||||
const std::string& filename, |
||||
efsw::Action action, |
||||
std::string oldFilename) override |
||||
{ |
||||
|
||||
// this is some gnarly BS here, probably tons
|
||||
// of memory leaks for now but it's working
|
||||
int ignored = 1; |
||||
auto the_path = fs::path(dir) / fs::path(filename); |
||||
string full_path = the_path.lexically_normal().string(); |
||||
|
||||
std::replace(full_path.begin(), |
||||
full_path.end(), '\\', '/'); |
||||
|
||||
int rc = git_ignore_path_is_ignored(&ignored, repo, full_path.c_str()); |
||||
|
||||
dbc::check(rc == 0, "git ignored failed."); |
||||
|
||||
if(!ignored) { |
||||
output(format("\nCHANGE: filename={} .gitignored?={}", full_path.c_str(), ignored)); |
||||
|
||||
changes = changes || !ignored; |
||||
} |
||||
} |
||||
|
||||
void reset_state() { |
||||
changes = false; |
||||
} |
||||
}; |
||||
|
||||
void run_build(GameEngine &game, const char* command) { |
||||
regex err_re("(.*?):([0-9]+):([0-9]+):\\s*(.*?):\\s*(.*)\n*"); |
||||
|
||||
char buffer[BUF_MAX]; // BUF_MAX is a define already?
|
||||
ofstream stats_out; |
||||
stats_out.open("stats.csv", ios::out | ios::app); |
||||
std::time_t tstamp = std::time(nullptr); |
||||
|
||||
dbc::check(stats_out.good(), "Error opening stats.csv file."); |
||||
dbc::pre("simple test", [&]() { return stats_out.good(); }); |
||||
|
||||
// need to catch the error message when the command is bad
|
||||
FILE *build_out = popen(command, "r"); |
||||
dbc::check(build_out != nullptr, "Failed to run command."); |
||||
|
||||
while(fgets(buffer, BUF_MAX, build_out) != nullptr) { |
||||
string line(buffer); // yeah, that's probably a problem
|
||||
|
||||
smatch err; |
||||
bool match = regex_match(line, err, err_re); |
||||
|
||||
if(match) { |
||||
string file_name = err[1].str(); |
||||
string lnumber = err[2].str(); |
||||
string col = err[3].str(); |
||||
string type = err[4].str(); |
||||
string message = err[5].str(); |
||||
|
||||
string result = format("{:%FT%T},{},{},{},{},{}\n", |
||||
fmt::localtime(tstamp), file_name, |
||||
lnumber, col, type, message); |
||||
|
||||
stats_out << result; |
||||
output(format("\nHIT WITH {} @ {}:{}:{} {}", type, file_name, lnumber, col, message)); |
||||
|
||||
game.hit(type); |
||||
|
||||
// refactor this
|
||||
if(game.is_dead()) { |
||||
output(format("YOU DIED!\n")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
stats_out.close(); |
||||
dbc::post("a post test", [&]() { return !stats_out.is_open(); }); |
||||
} |
||||
|
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
git_repository* repo = nullptr; |
||||
|
||||
try { |
||||
dbc::check(argc == 3, "USAGE: watchgit PATH BUILD_CMD"); |
||||
const char *git_path = argv[1]; |
||||
const char *build_cmd = argv[2]; |
||||
|
||||
output(format("Using build command: {}", build_cmd)); |
||||
efsw::FileWatcher* fileWatcher = new efsw::FileWatcher(); |
||||
dbc::check(fileWatcher != nullptr, "Failed to create filewatcher."); |
||||
|
||||
git_libgit2_init(); |
||||
|
||||
int err = git_repository_open(&repo, git_path); |
||||
dbc::check(err == 0, git_error_last()->message); |
||||
if(argc != 3) { |
||||
fmt::println("USAGE: watchgit PATH BUILD_CMD"); |
||||
return 1; |
||||
} else { |
||||
const char *git_path = argv[1]; |
||||
const char *build_cmd = argv[2]; |
||||
|
||||
UpdateListener* listener = new UpdateListener(repo); |
||||
dbc::check(listener != nullptr, "Failed to create listener."); |
||||
GUI gui; |
||||
GameEngine game{100}; |
||||
|
||||
output(format("Watching directory {} for changes...\n", git_path)); |
||||
efsw::WatchID wid = fileWatcher->addWatch(git_path, listener, true); |
||||
auto builder = Builder(gui, game); |
||||
builder.run(git_path, build_cmd); |
||||
|
||||
GameEngine game{100}; |
||||
|
||||
int rc = main_loop(game, [&] { |
||||
fileWatcher->watch(); |
||||
|
||||
if(listener->changes) { |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||
output(format("CHANGES! Running build {}", build_cmd)); |
||||
run_build(game, build_cmd); |
||||
listener->reset_state(); |
||||
} |
||||
return 0; |
||||
}); |
||||
|
||||
dbc::check(rc == 0, "Invalid return from main_loop."); |
||||
|
||||
git_libgit2_shutdown(); |
||||
} catch(dbc::Error &err) { |
||||
output(format("ERROR: {}\n", err.message)); |
||||
if(repo != nullptr) git_repository_free(repo); |
||||
git_libgit2_shutdown(); |
||||
return 1; |
||||
} |
||||
return 1; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,31 @@ |
||||
#include "watcher.hpp" |
||||
#include <filesystem> |
||||
using namespace std; |
||||
namespace fs = std::filesystem; |
||||
|
||||
void UpdateListener::handleFileAction(efsw::WatchID watchid, |
||||
const std::string& dir, |
||||
const std::string& filename, |
||||
efsw::Action action, |
||||
std::string oldFilename) |
||||
{ |
||||
|
||||
// this is some gnarly BS here, probably tons
|
||||
// of memory leaks for now but it's working
|
||||
int ignored = 1; |
||||
auto the_path = fs::path(dir) / fs::path(filename); |
||||
string full_path = the_path.lexically_normal().string(); |
||||
|
||||
std::replace(full_path.begin(), |
||||
full_path.end(), '\\', '/'); |
||||
|
||||
int rc = git_ignore_path_is_ignored(&ignored, repo, full_path.c_str()); |
||||
|
||||
if(!ignored) { |
||||
changes = changes || !ignored; |
||||
} |
||||
} |
||||
|
||||
void UpdateListener::reset_state() { |
||||
changes = false; |
||||
} |
@ -0,0 +1,20 @@ |
||||
#pragma once |
||||
#include <efsw/efsw.hpp> |
||||
#include <git2.h> |
||||
#include <string> // for operator+, to_string |
||||
|
||||
class UpdateListener : public efsw::FileWatchListener { |
||||
public: |
||||
bool changes = false; |
||||
git_repository* repo = nullptr; |
||||
|
||||
UpdateListener(git_repository *r) : repo(r) {}; |
||||
|
||||
void handleFileAction(efsw::WatchID watchid, |
||||
const std::string& dir, |
||||
const std::string& filename, |
||||
efsw::Action action, |
||||
std::string oldFilename) override; |
||||
|
||||
void reset_state(); |
||||
}; |
Loading…
Reference in new issue