From 136966aeac7ac000d5b0aadc689e40a61aa5efd5 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Fri, 7 Nov 2025 15:15:16 +0100 Subject: Adding git features --- run_and_record/.nix/derivation.nix | 2 + run_and_record/SConstruct | 3 +- run_and_record/c++/git.hpp | 88 +++++++++++++++++++++++++++++++++++++ run_and_record/c++/main.cpp | 89 ++++++++++++-------------------------- run_and_record/c++/schema.hpp | 58 +++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 62 deletions(-) create mode 100644 run_and_record/c++/git.hpp create mode 100644 run_and_record/c++/schema.hpp diff --git a/run_and_record/.nix/derivation.nix b/run_and_record/.nix/derivation.nix index 089c7cb..ed20cbe 100644 --- a/run_and_record/.nix/derivation.nix +++ b/run_and_record/.nix/derivation.nix @@ -1,6 +1,7 @@ { stdenv , scons , forstio +, libgit2 }: stdenv.mkDerivation { @@ -18,6 +19,7 @@ stdenv.mkDerivation { forstio.codec-json forstio.remote forstio.remote-filesystem + libgit2 ]; src = ./..; diff --git a/run_and_record/SConstruct b/run_and_record/SConstruct index 9dbf18f..8dcd782 100644 --- a/run_and_record/SConstruct +++ b/run_and_record/SConstruct @@ -49,7 +49,8 @@ env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[], CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'], LIBS=[ 'forstio-core', - 'forstio-async' + 'forstio-async', + 'git2' ] ) env.__class__.add_source_files = add_kel_source_files diff --git a/run_and_record/c++/git.hpp b/run_and_record/c++/git.hpp new file mode 100644 index 0000000..c145e01 --- /dev/null +++ b/run_and_record/c++/git.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include + +#include + +#include "schema.hpp" + +namespace kel { +saw::error_or> is_clean_git_repo(){ + saw::data git_data; + + git_repository *repo = nullptr; + { + int error = git_repository_open_ext(&repo, ".", 0, nullptr); + if (error < 0) { + // const git_error *e = git_error_last(); + git_libgit2_shutdown(); + return saw::make_error("Not a git repository"); + } + } + + { + git_status_options status_opts = GIT_STATUS_OPTIONS_INIT; + status_opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + status_opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; + + git_status_list* status_list = nullptr; + int error = git_status_list_new(&status_list, repo, &status_opts); + if (error < 0) { + git_repository_free(repo); + git_libgit2_shutdown(); + return saw::make_error("Failed to get git status"); + } + + size_t count = git_status_list_entrycount(status_list); + if(count > 0){ + git_status_list_free(status_list); + git_repository_free(repo); + git_libgit2_shutdown(); + return saw::make_error("Git repo is not clean"); + } + git_status_list_free(status_list); + } + + git_oid oid; + { + if(git_reference_name_to_id(&oid, repo, "HEAD") < 0){ + git_repository_free(repo); + git_libgit2_shutdown(); + return saw::make_error("Failed to read HEAD"); + } + } + + std::array hash_chars; + hash_chars[GIT_OID_HEXSZ] = 0; + git_oid_tostr(&hash_chars[0], hash_chars.size(), &oid); + hash_chars[GIT_OID_HEXSZ] = 0; + + auto& commit = git_data.template get<"commit">(); + commit.set(std::string{hash_chars.data()}); + + git_remote* remote = nullptr; + auto& origin = git_data.template get<"origin">(); + { + int error = git_remote_lookup(&remote, repo, "origin"); + if (error < 0) { + git_repository_free(repo); + git_libgit2_shutdown(); + return saw::make_error("Failed to find origin remote"); + } + const char* url = git_remote_url(remote); + if(not url) { + git_remote_free(remote); + git_repository_free(repo); + git_libgit2_shutdown(); + return saw::make_error("Failed to get origin remote url"); + } + + origin.set(std::string{url}); + } + + git_remote_free(remote); + git_repository_free(repo); + git_libgit2_shutdown(); + return git_data; +} +} diff --git a/run_and_record/c++/main.cpp b/run_and_record/c++/main.cpp index 8440d67..d28629f 100644 --- a/run_and_record/c++/main.cpp +++ b/run_and_record/c++/main.cpp @@ -10,56 +10,12 @@ #include #include +#include "git.hpp" +#include "schema.hpp" + +extern char** environ; + namespace kel { -namespace sch { -using namespace saw::schema; - -using RarConfig = Struct< ->; - -// Additionally record the files which are needed to run the simulation -using RarArgsTuple = Tuple< - Array ->; - -using RarArgs = Args< - RarConfig, - RarArgsTuple ->; - -using RarFileData = Struct< - Member< - Member< - Array< - Struct< - Member, - Member, "arguments"> - > - >, - >, "commands">, - Member< - Array< - Struct< - Member, - Member - > - >, "env">, - Member< - Struct< - Member, - Member - >, - "git">, - Member< - Array< - Struct< - Member, "command">, - Member, - Member - > - >, "meta"> ->; -} /** * Check if HOME env variable is set and where it points to. @@ -135,7 +91,7 @@ saw::error_or generate_data_dir_name(const std::string_view& bin_na thread_local std::mt19937 generator{std::random_device{}()}; std::uniform_int_distribution distribution(0, chars.size() - 1); - for (size_t i = 0; i < length; ++i){ + for (size_t i = 0; i < 8; ++i){ oss << chars[distribution(generator)]; } } @@ -143,25 +99,21 @@ saw::error_or generate_data_dir_name(const std::string_view& bin_na return oss.str(); } -extern char** environ; - /** * Record the environment */ -saw::error_or record_environment(saw::data& df){ +saw::error_or record_environment(saw::data& df_env){ saw::data env_size{0u}; for(char** env = environ; *env != nullptr; ++env){ ++env_size; } - auto& df_env = df.template get<"env">(); - - df_env = {env_size}; + df_env = {saw::data>{{env_size}}}; saw::data i{0u}; for(char** env = environ; *env != nullptr; ++env){ - df_env.at(i).set(std::to_string(env)); + df_env.at(i).set(std::string(*env)); ++i; } @@ -202,9 +154,9 @@ saw::error_or kel_main(int argc, char** argv){ saw::data args; auto eo_home = get_home_env(); if(eo_home.is_error()){ - return std::move(eov.get_error()); + return std::move(eo_home.get_error()); } - auto& home = eov.get_value(); + auto& home = eo_home.get_value(); auto data_dir = home / ".local" / "kel" / "run_and_record"; // @@ -221,7 +173,7 @@ saw::error_or kel_main(int argc, char** argv){ // Read the user config file for recording { auto conf_file = home / ".config" / "kel" / "run_and_record.json"; - auto eo_file = simple_read_file(conf_file); + auto eo_file = saw::easy::read_and_decode_file(conf_file); if(eo_file.is_error()){ return std::move(eo_file.get_error()); @@ -247,6 +199,16 @@ saw::error_or kel_main(int argc, char** argv){ return eov; } } + + { + auto eo_git = is_clean_git_repo(); + if(eo_git.is_error()){ + return std::move(eo_git.get_error()); + } + auto& v_git = eo_git.get_value(); + data_for_file.template get<"git">() = v_git; + } + // sep_pos+1 til end int argc_prog = argc - (sep_pos+1); { @@ -255,8 +217,13 @@ saw::error_or kel_main(int argc, char** argv){ return eov; } } + + if(not std::filesystem::create_directory(data_full_dir)){ + return saw::make_error("Couldn't create directory for file"); + } + { - auto eov = easy::write_file(data_full_dir, data_for_file); + auto eov = saw::easy::encode_and_write_file(data_full_dir / "data.json", data_for_file); if(eov.is_error()){ return eov; } diff --git a/run_and_record/c++/schema.hpp b/run_and_record/c++/schema.hpp new file mode 100644 index 0000000..140e81b --- /dev/null +++ b/run_and_record/c++/schema.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +namespace kel { +namespace sch { +using namespace saw::schema; + +using RarConfig = Struct< +>; + +// Additionally record the files which are needed to run the simulation +using RarArgsTuple = Tuple< +>; + +using RarGit = Struct< + Member, + Member +>; + +using RarArgs = Args< + RarConfig, + RarArgsTuple +>; + +using RarEnv = Array; + +using RarFileData = Struct< + Member< + Array< + Struct< + Member, + Member, "arguments"> + > + >, + "commands" + >, + Member< + RarEnv, + "env" + >, + Member< + RarGit, + "git" + >, + Member< + Array< + Struct< + Member, "command">, + Member, + Member + > + >, + "meta" + > +>; +} +} -- cgit v1.2.3