From 1f9e0d863eaed012addabcacf27cc0a0f953d2e1 Mon Sep 17 00:00:00 2001 From: TiagoRG Date: Sat, 27 Jan 2024 16:33:12 +0000 Subject: [PATCH] Update program - Now tracks Created files - Error handling --- .gitignore | 3 +- README.md | 4 +- main.cpp | 114 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 3b88dcc..794b0b1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ CMakeFiles/ CMakeCache.txt Makefile cmake_install.cmake -gh-wh-handler -config.json +bin/ \ No newline at end of file diff --git a/README.md b/README.md index 023f0bc..7f10ae3 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The configuration file should be a JSON file with the following format: "repo_full_name": { "branch": "target_branch", "files": { - "remote_path": "local_path", + "remote_path": "local_path" } } }, @@ -45,4 +45,4 @@ The configuration file should be a JSON file with the following format: ## Endpoint -Currently the only endpoint for the application is /update-files +Currently, the only endpoint for the application is /update-files diff --git a/main.cpp b/main.cpp index 88eaab8..6501c08 100644 --- a/main.cpp +++ b/main.cpp @@ -5,15 +5,23 @@ #include #include +void signal_handler(const int signum) { + // std::cout << "Interrupt signal (" << signum << ") received.\n"; + std::cout << "Exiting..." << std::endl; + std::exit(signum); +} + int main(int argc, char **argv) { // Check for config file argument, exit if it's not there - if (argc != 2) { + if (argc > 2) { std::cerr << "Usage: " << 0[argv] << " " << std::endl; return 1; } + std::string config_file_path = argc == 2 ? 1[argv] : "/etc/gh_wh_handler/config.json"; + // Open config file, exit if it fails - std::ifstream config_file(1[argv]); + std::ifstream config_file(config_file_path); if (!config_file.is_open()) { std::cerr << "Failed to open config.json" << std::endl; return 1; @@ -57,24 +65,36 @@ int main(int argc, char **argv) { } try { + std::string ref; + std::string repo; + bool is_private; + std::string token; // Parse the payload - std::string ref = payload["ref"]; - size_t last_slash = ref.find_last_of('/'); - if (last_slash != std::string::npos && last_slash + 1 < ref.length()) - ref = ref.substr(last_slash + 1); - std::string repo = payload["repository"]["full_name"]; - bool is_private = payload["repository"]["private"]; - std::string token = std::string(); - if (is_private) { - if (tokens.find(repo) == tokens.end()) { - printf("No token configured for private repo %s\n", repo.c_str()); - nlohmann::json response = { - {"status", 403}, - {"error", "No token configured for private repo"} - }; - return crow::response(403, response.dump()); + try { + ref = payload["ref"]; + if (size_t last_slash = ref.find_last_of('/'); last_slash != std::string::npos && last_slash + 1 < ref.length()) + ref = ref.substr(last_slash + 1); + repo = payload["repository"]["full_name"]; + is_private = payload["repository"]["private"]; + token = std::string(); + if (is_private) { + if (tokens.find(repo) == tokens.end()) { + printf("No token configured for private repo %s\n", repo.c_str()); + nlohmann::json response = { + {"status", 403}, + {"error", "No token configured for private repo"} + }; + return crow::response(403, response.dump()); + } + token = tokens[repo]; } - token = tokens[repo]; + } catch (const std::exception &e) { + std::cerr << "Error parsing payload: " << e.what() << std::endl; + nlohmann::json response = { + {"status", 400}, + {"error", "Invalid JSON payload"} + }; + return crow::response(400, response.dump()); } printf("Received push to %s:%s (private: %s)\n", repo.c_str(), ref.c_str(), is_private ? "true" : "false"); @@ -93,8 +113,7 @@ int main(int argc, char **argv) { nlohmann::json repo_data; bool is_valid_branch = false; for (auto c_repo = repos.begin(); c_repo != repos.end(); ++c_repo) { - std::string c_repo_name = c_repo.key(); - if (c_repo_name != repo) continue; + if (const std::string &c_repo_name = c_repo.key(); c_repo_name != repo) continue; if (c_repo.value()["branch"] != ref) continue; is_valid_branch = true; repo_data = c_repo.value(); @@ -119,33 +138,46 @@ int main(int argc, char **argv) { return crow::response(404, response.dump()); } + // Get list with modified files + std::vector> modified_files; + for (auto &commit : payload["commits"]) { + for (auto &file : commit["modified"]) { + std::string file_path = file; + if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue; + std::vector file_data = {file_path, "modified"}; + modified_files.push_back(file_data); + } + for (auto &file : commit["added"]) { + std::string file_path = file; + if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue; + std::vector file_data = {file_path, "added"}; + modified_files.push_back(file_data); + } + } + // Download files nlohmann::json response = { {"status", 200}, {"file_count", 0}, {"updated", nlohmann::json::array()} }; - for (auto &commit : payload["commits"]) { - for (auto &file : commit["modified"]) { - std::string file_path = file; - if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue; + for (std::vector &file_data : modified_files) { + std::string file_path = file_data[0]; - std::string path = repos[repo]["files"][file_path]; - try { - std::filesystem::create_directories(path.substr(0, path.find_last_of('/'))); - } catch (const std::exception &e) { - std::cerr << "Failed to create directories for " << path << ": " << e.what() << std::endl; - continue; - } - - std::string command = "curl -s https://raw.githubusercontent.com/" + repo + "/" + ref + "/" + file_path + " -o " + path; - if (is_private) - command += " -H 'Authorization: token " + token + "'"; - std::system(command.c_str()); - printf("Updated %s\n", path.c_str()); - response["file_count"] = response["file_count"].get() + 1; - response["updated"].push_back(file_path); + std::string path = repos[repo]["files"][file_path]; + try { + std::filesystem::create_directories(path.substr(0, path.find_last_of('/'))); + } catch (const std::exception &e) { + std::cerr << "Failed to create directories for " << path << ": " << e.what() << std::endl; + continue; } + + std::string command = "curl -s https://raw.githubusercontent.com/" + repo + "/" + ref + "/" + file_path + " -o " + path; + if (is_private) command += " -H 'Authorization: token " + token + "'"; + std::system(command.c_str()); + printf("%s %s\n", file_data[1] == "added" ? "Created" : "Updated", path.c_str()); + response["file_count"] = response["file_count"].get() + 1; + response["updated"].push_back(file_path); } return crow::response(200, response.dump()); @@ -155,5 +187,9 @@ int main(int argc, char **argv) { } }); + std::signal(SIGINT, signal_handler); + app.port(port).multithreaded().run(); + + return 0; }