First drop the game's core mechanic that compiles.
This commit is contained in:
		
						commit
						5f87d9846c
					
				
					 11 changed files with 607 additions and 0 deletions
				
			
		
							
								
								
									
										12
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| .*.sw* | ||||
| .DS_Store | ||||
| *.sqlite3 | ||||
| *.sqlite3-wal | ||||
| *.sqlite3-shm | ||||
| debug | ||||
| coverage/ | ||||
| .coverage | ||||
| builddir | ||||
| subprojects | ||||
| *.csv | ||||
| *.exe | ||||
							
								
								
									
										1
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| Copyright (C) 2024 Zed A. Shaw | ||||
							
								
								
									
										38
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| A game I'm working. It's a weird one. | ||||
| 
 | ||||
| Right now I've got a command that watches your files for changes, and runs a build command. It's | ||||
| entirely overengineered for this purpose, but it has what I'll need later.  To build it do this: | ||||
| 
 | ||||
| ```shell | ||||
| ./scripts/reset_build.ps1 | ||||
| meson compile -C builddir | ||||
| ``` | ||||
| 
 | ||||
| If you get a bad compile because of libgit2's `src/util/process.h` then do this: | ||||
| 
 | ||||
| ```shell | ||||
| cp patches/process.h subprojects/libgit2/src/util/ | ||||
| meson compile -C builddir | ||||
| ``` | ||||
| 
 | ||||
| I don't know why it fails at this, and only on Windows but I've talked to them repeatedly and it's | ||||
| mostly "works for me" responses.  I also can't figure out how Meson exactly applies patches.  I've | ||||
| generated every possible patch I can and Meson just can't apply them. | ||||
| 
 | ||||
| Once it's running, we have even more annoying BS to deal with, and that's because Meson doesn't | ||||
| actually statically compile efsw or libgit2.  Even though I said `--default-librart=static --prefer-static` in the setup it just ignores that and makes DLLs.  The "fix" for this asinine stupidity is this: | ||||
| 
 | ||||
| ```shell | ||||
| meson devenv -C builddir | ||||
| cd .. | ||||
| cp builddir/watchgit . | ||||
| ./watchgit . "meson compile -C builddir | ||||
| ``` | ||||
| 
 | ||||
| Do all that garbage and yay, this little program runs. Finally. | ||||
| 
 | ||||
| ## Future Changes | ||||
| 
 | ||||
| 1. If I can't figure out why libgit2 has compilation errors in `src/util/process.h` then I may just rip it out and just shell out to `git` directly. | ||||
| 2. Ultimately I can jsut use efsw to watch the directory for all changes, but I wanted to only focus on what's in git.  Oh well. | ||||
| 3. I also have to find out why efsw and libgit2 refuse to compile statically.  Once I do that I can static compile `watchgit` and then work on the next part of the game. | ||||
							
								
								
									
										49
									
								
								dbc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								dbc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| #include <string> | ||||
| #include <fmt/core.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace dbc { | ||||
|   class Error { | ||||
|     public: | ||||
|       const string message; | ||||
|       Error(string m) : message{m} {} | ||||
|       Error(const char *m) : message{m} {} | ||||
|   }; | ||||
| 
 | ||||
|   class CheckError : public Error {}; | ||||
| 
 | ||||
|   class SentinelError : public Error {}; | ||||
|   class PreCondError : public Error {}; | ||||
|   class PostCondError : public Error {}; | ||||
| 
 | ||||
|   void log(const string &message) { | ||||
|     fmt::print("{}\n", message); | ||||
|   } | ||||
| 
 | ||||
|   void sentinel(const string &message) { | ||||
|     string err = fmt::format("[SENTINEL!] {}\n", message); | ||||
|     throw SentinelError{err}; | ||||
|   } | ||||
| 
 | ||||
|   void pre(const string &message, std::function<bool()> tester) { | ||||
|     if(!tester()) { | ||||
|       string err = fmt::format("[PRE!] {}\n", message); | ||||
|       throw PreCondError{err}; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void post(const string &message, std::function<bool()> tester) { | ||||
|     if(!tester()) { | ||||
|       string err = fmt::format("[POST!] {}\n", message); | ||||
|       throw PostCondError{err}; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void check(bool test, const string &message) { | ||||
|     if(!test) { | ||||
|       string err = fmt::format("[CHECK!] {}\n", message); | ||||
|       throw CheckError{err}; | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										10
									
								
								efsw.wrap
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								efsw.wrap
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| [wrap-git] | ||||
| url = https://github.com/SpartanJ/efsw.git | ||||
| revision = 1.3.1 | ||||
| depth = 1 | ||||
| # patch_filename = | ||||
| # patch_hash = | ||||
| 
 | ||||
| 
 | ||||
| [provide] | ||||
| efsw = efsw_dep | ||||
							
								
								
									
										12
									
								
								libgit2.wrap
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libgit2.wrap
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| [wrap-file] | ||||
| directory = libgit2-1.8.1 | ||||
| source_url = https://github.com/libgit2/libgit2/archive/refs/tags/v1.8.1.tar.gz | ||||
| source_filename = v1.8.1.tar.gz | ||||
| source_hash = 8c1eaf0cf07cba0e9021920bfba9502140220786ed5d8a8ec6c7ad9174522f8e | ||||
| wrapdb_version = 2.4.1-3 | ||||
| # patch_filename = | ||||
| # patch_hash = | ||||
| 
 | ||||
| 
 | ||||
| [provide] | ||||
| libgit2 = libgit2_dep | ||||
							
								
								
									
										26
									
								
								meson.build
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								meson.build
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| project('lcppthw', 'cpp', | ||||
|     default_options: ['cpp_std=c++20']) | ||||
| 
 | ||||
| cmake = import('cmake') | ||||
| opts = cmake.subproject_options() | ||||
| opts.add_cmake_defines({ | ||||
|   'USE_ICONV': false, | ||||
|   'USE_SSH': false, | ||||
|   'USE_NTLMCLIENT': false, | ||||
|   'BUILD_SHARED_LIBS': true, | ||||
|   'BUILD_TESTS': false, | ||||
|   }) | ||||
| libgit2_proj = cmake.subproject('libgit2', options: opts) | ||||
| libgit2package_dep = libgit2_proj.dependency('libgit2package') | ||||
| 
 | ||||
| efsw_proj = cmake.subproject('efsw') | ||||
| efsw_dep = efsw_proj.dependency('efsw') | ||||
| 
 | ||||
| fmt = dependency('fmt') | ||||
| 
 | ||||
| dependencies = [ | ||||
|   fmt, libgit2package_dep, efsw_dep, | ||||
| ] | ||||
| 
 | ||||
| executable('watchgit', 'watchgit.cpp', | ||||
|   dependencies: dependencies) | ||||
							
								
								
									
										223
									
								
								patches/process.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								patches/process.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,223 @@ | |||
| /*
 | ||||
|  * Copyright (C) the libgit2 contributors. All rights reserved. | ||||
|  * | ||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with | ||||
|  * a Linking Exception. For full terms see the included COPYING file. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef INCLUDE_process_h__ | ||||
| #define INCLUDE_process_h__ | ||||
| 
 | ||||
| typedef struct git_str git_str; | ||||
| typedef struct git_process git_process; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	unsigned int capture_in  : 1, | ||||
| 	             capture_out : 1, | ||||
| 	             capture_err : 1, | ||||
| 	             exclude_env : 1; | ||||
| 
 | ||||
| 	char *cwd; | ||||
| } git_process_options; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	GIT_PROCESS_STATUS_NONE, | ||||
| 	GIT_PROCESS_STATUS_NORMAL, | ||||
| 	GIT_PROCESS_STATUS_ERROR | ||||
| } git_process_result_status; | ||||
| 
 | ||||
| #define GIT_PROCESS_RESULT_INIT { GIT_PROCESS_STATUS_NONE } | ||||
| 
 | ||||
| typedef struct { | ||||
| 	git_process_result_status status; | ||||
| 	int exitcode; | ||||
| 	int signal; | ||||
| } git_process_result; | ||||
| 
 | ||||
| #define GIT_PROCESS_OPTIONS_INIT { 0 } | ||||
| 
 | ||||
| #ifdef GIT_WIN32 | ||||
| # define p_pid_t DWORD | ||||
| #else | ||||
| # define p_pid_t pid_t | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * Create a new process.  The command to run should be specified as the | ||||
|  * element of the `arg` array, execv-style. This should be the full path | ||||
|  * to the command to run, the PATH is not obeyed. | ||||
|  * | ||||
|  * This function will add the given environment variables (in `env`) | ||||
|  * to the current environment.  Operations on environment variables | ||||
|  * are not thread safe, so you may not modify the environment during | ||||
|  * this call.  You can avoid this by setting `exclude_env` in the | ||||
|  * options and providing the entire environment yourself. | ||||
|  * | ||||
|  * @param out location to store the process | ||||
|  * @param args the command (with arguments) to run | ||||
|  * @param args_len the length of the args array | ||||
|  * @param env environment variables to add (or NULL) | ||||
|  * @param env_len the length of the env len | ||||
|  * @param opts the options for creating the process | ||||
|  * @return 0 or an error code | ||||
|  */ | ||||
| extern int git_process_new( | ||||
| 	git_process **out, | ||||
| 	const char **args, | ||||
| 	size_t args_len, | ||||
| 	const char **env, | ||||
| 	size_t env_len, | ||||
| 	git_process_options *opts); | ||||
| 
 | ||||
| /**
 | ||||
|  * Create a new process. The command to run should be specified as the | ||||
|  * `cmdline` option - which is the full text of the command line as it | ||||
|  * would be specified or run by a user. The command to run will be | ||||
|  * looked up in the PATH. | ||||
|  * | ||||
|  * On Unix, this will be executed by the system's shell (`/bin/sh`) | ||||
|  * and may contain _Bourne-style_ shell quoting rules. On Windows, | ||||
|  * this will be passed to `CreateProcess`, and similarly, may | ||||
|  * contain _Windows-style_ shell quoting rules. | ||||
|  * | ||||
|  * This function will add the given environment variables (in `env`) | ||||
|  * to the current environment.  Operations on environment variables | ||||
|  * are not thread safe, so you may not modify the environment during | ||||
|  * this call.  You can avoid this by setting `exclude_env` in the | ||||
|  * options and providing the entire environment yourself. | ||||
|  */ | ||||
| extern int git_process_new_from_cmdline( | ||||
| 	git_process **out, | ||||
| 	const char *cmdline, | ||||
| 	const char **env, | ||||
| 	size_t env_len, | ||||
| 	git_process_options *opts); | ||||
| 
 | ||||
| #ifdef GIT_WIN32 | ||||
| 
 | ||||
| extern int git_process__appname( | ||||
| 	git_str *out, | ||||
| 	const char *cmdline); | ||||
| 
 | ||||
| /* Windows path parsing is tricky; this helper function is for testing. */ | ||||
| extern int git_process__cmdline( | ||||
| 	git_str *out, | ||||
| 	const char **in, | ||||
| 	size_t in_len); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Whether the given string looks like a command line option (starts | ||||
|  * with a dash). This is useful for examining strings that will become | ||||
|  * cmdline arguments to ensure that they are not erroneously treated | ||||
|  * as an option. For example, arguments to `ssh`. | ||||
|  */ | ||||
| static __inline__ bool git_process__is_cmdline_option(const char *str) | ||||
| { | ||||
| 	return (str && str[0] == '-'); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Start the process. | ||||
|  * | ||||
|  * @param process the process to start | ||||
|  * @return 0 or an error code | ||||
|  */ | ||||
| extern int git_process_start(git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns the process id of the process. | ||||
|  * | ||||
|  * @param out pointer to a pid_t to store the process id | ||||
|  * @param process the process to query | ||||
|  * @return 0 or an error code | ||||
|  */ | ||||
| extern int git_process_id(p_pid_t *out, git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Read from the process's stdout.  The process must have been created with | ||||
|  * `capture_out` set to true. | ||||
|  * | ||||
|  * @param process the process to read from | ||||
|  * @param buf the buf to read into | ||||
|  * @param count maximum number of bytes to read | ||||
|  * @return number of bytes read or an error code | ||||
|  */ | ||||
| extern ssize_t git_process_read(git_process *process, void *buf, size_t count); | ||||
| 
 | ||||
| /**
 | ||||
|  * Read from the process's stderr.  The process must have been created with | ||||
|  * `capture_err` set to true. | ||||
|  * | ||||
|  * @param process the process to read from | ||||
|  * @param buf the buf to read into | ||||
|  * @param count maximum number of bytes to read | ||||
|  * @return number of bytes read or an error code | ||||
|  */ | ||||
| extern ssize_t git_process_read_err(git_process *process, void *buf, size_t count); | ||||
| 
 | ||||
| /**
 | ||||
|  * Write to the process's stdin.  The process must have been created with | ||||
|  * `capture_in` set to true. | ||||
|  * | ||||
|  * @param process the process to write to | ||||
|  * @param buf the buf to write | ||||
|  * @param count maximum number of bytes to write | ||||
|  * @return number of bytes written or an error code | ||||
|  */ | ||||
| extern ssize_t git_process_write(git_process *process, const void *buf, size_t count); | ||||
| 
 | ||||
| /**
 | ||||
|  * Wait for the process to finish. | ||||
|  * | ||||
|  * @param result the result of the process or NULL | ||||
|  * @param process the process to wait on | ||||
|  */ | ||||
| extern int git_process_wait(git_process_result *result, git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Close the input pipe from the child. | ||||
|  * | ||||
|  * @param process the process to close the pipe on | ||||
|  */ | ||||
| extern int git_process_close_in(git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Close the output pipe from the child. | ||||
|  * | ||||
|  * @param process the process to close the pipe on | ||||
|  */ | ||||
| extern int git_process_close_out(git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Close the error pipe from the child. | ||||
|  * | ||||
|  * @param process the process to close the pipe on | ||||
|  */ | ||||
| extern int git_process_close_err(git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Close all resources that are used by the process.  This does not | ||||
|  * wait for the process to complete. | ||||
|  * | ||||
|  * @parma process the process to close | ||||
|  */ | ||||
| extern int git_process_close(git_process *process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Place a human-readable error message in the given git buffer. | ||||
|  * | ||||
|  * @param msg the buffer to store the message | ||||
|  * @param result the process result that produced an error | ||||
|  */ | ||||
| extern int git_process_result_msg(git_str *msg, git_process_result *result); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free a process structure | ||||
|  * | ||||
|  * @param process the process to free | ||||
|  */ | ||||
| extern void git_process_free(git_process *process); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										14
									
								
								scripts/reset_build.ps1
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								scripts/reset_build.ps1
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| mv .\subprojects\packagecache . | ||||
| rm -recurse -force .\subprojects\,.\builddir\ | ||||
| mkdir subprojects | ||||
| mv .\packagecache .\subprojects\ | ||||
| cp *.wrap subprojects | ||||
| # cp -recurse -force packagefiles subprojects | ||||
| mkdir builddir | ||||
| meson wrap install fmt | ||||
| meson wrap install sqlite3 | ||||
| meson wrap install sqlitecpp | ||||
| meson wrap install ftxui | ||||
| # $env:CC="clang" | ||||
| # $env:CXX="clang++" | ||||
| meson setup --default-library=static --prefer-static builddir | ||||
							
								
								
									
										14
									
								
								scripts/reset_build.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								scripts/reset_build.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #!/usr/bin/env bash | ||||
| set -e | ||||
| 
 | ||||
| mv -f ./subprojects/packagecache . | ||||
| rm -rf subprojects builddir | ||||
| mkdir subprojects | ||||
| mv packagecache ./subprojects/ | ||||
| mkdir builddir | ||||
| cp *.wrap subprojects | ||||
| meson wrap install fmt | ||||
| meson wrap install sqlite3 | ||||
| meson wrap install sqlitecpp | ||||
| meson wrap install ftxui | ||||
| meson setup builddir | ||||
							
								
								
									
										208
									
								
								watchgit.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								watchgit.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,208 @@ | |||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <fstream> | ||||
| #include <fmt/core.h> | ||||
| #include <regex> | ||||
| #include <string> | ||||
| #include <iterator> | ||||
| #include <ctime> | ||||
| #include "dbc.h" | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include "test.hpp" | ||||
| #include <git2.h> | ||||
| #include <efsw/efsw.hpp> | ||||
| #include <regex> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace fmt; | ||||
| 
 | ||||
| #define BUF_MAX 1024 | ||||
| 
 | ||||
| /*
 | ||||
|  * No idea what the semantics of this are.  Will need | ||||
|  * to research git's dumb terminology to figure out why | ||||
|  * they have 4 different versions of the path for status. | ||||
|  */ | ||||
| const char *unfuck_path(const git_status_entry *entry) { | ||||
|   if(entry->head_to_index != nullptr) { | ||||
|     if(entry->head_to_index->new_file.path) { | ||||
|       return entry->head_to_index->new_file.path; | ||||
|     } else { | ||||
|       return entry->head_to_index->old_file.path; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if(entry->index_to_workdir != nullptr) { | ||||
|     if(entry->index_to_workdir->new_file.path) { | ||||
|       return entry->index_to_workdir->new_file.path; | ||||
|     } else { | ||||
|       return entry->index_to_workdir->old_file.path; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| void add_status(const git_status_entry *entry, unsigned int status_flags, vector<string> &updates) { | ||||
|   const char *path = unfuck_path(entry); | ||||
| 
 | ||||
|   if(status_flags & GIT_STATUS_WT_NEW | ||||
|       || status_flags & GIT_STATUS_INDEX_NEW) | ||||
|   { | ||||
|     updates.push_back(string{path}); | ||||
|   } | ||||
| 
 | ||||
|   if(status_flags & GIT_STATUS_WT_MODIFIED | ||||
|       || status_flags & GIT_STATUS_INDEX_MODIFIED) | ||||
|   { | ||||
|     updates.push_back(string{path}); | ||||
|   } | ||||
| 
 | ||||
|   // need to confirm this gets the new name
 | ||||
|   if(status_flags & GIT_STATUS_WT_RENAMED | ||||
|       || status_flags & GIT_STATUS_INDEX_RENAMED) | ||||
|   { | ||||
|     updates.push_back(string{path}); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class UpdateListener : public efsw::FileWatchListener { | ||||
|   public: | ||||
|     bool changes = false; | ||||
| 
 | ||||
|     void handleFileAction(efsw::WatchID watchid, | ||||
|         const std::string& dir, | ||||
|         const std::string& filename, | ||||
|         efsw::Action action, | ||||
|         std::string oldFilename) override | ||||
|     { | ||||
|       changes = true; | ||||
| 
 | ||||
|       switch(action) { | ||||
|         case efsw::Actions::Add: | ||||
|           print("ADD {} {} {}\n", dir, filename, oldFilename); | ||||
|           break; | ||||
|         case efsw::Actions::Delete: | ||||
|           print("DEL {} {} {}\n", dir, filename, oldFilename); | ||||
|           break; | ||||
|         case efsw::Actions::Modified: | ||||
|           print("MOD {} {} {}\n", dir, filename, oldFilename); | ||||
|           break; | ||||
|         case efsw::Actions::Moved: | ||||
|           print("MOV {} {} {}\n", dir, filename, oldFilename); | ||||
|           break; | ||||
|         default: | ||||
|           dbc::sentinel("Unknown efsw action."); | ||||
|       } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void reset_state() { | ||||
|       changes = false; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void list_git_changes(git_repository* repo) { | ||||
|   git_status_options opts = GIT_STATUS_OPTIONS_INIT; | ||||
|   git_status_list *statuses = nullptr; | ||||
| 
 | ||||
|   //TODO: does this leak?
 | ||||
|   int err = git_status_list_new(&statuses, repo, &opts); | ||||
|   dbc::check(err == 0, git_error_last()->message); | ||||
|   size_t count = git_status_list_entrycount(statuses); | ||||
| 
 | ||||
|   vector<string> updates; | ||||
| 
 | ||||
|   for(size_t i=0; i < count; i++) { | ||||
|     const git_status_entry *entry = git_status_byindex(statuses, i); | ||||
|     add_status(entry, entry->status, updates); | ||||
|   } | ||||
| 
 | ||||
|   for(string path : updates) { | ||||
|     print("PATH {}\n", path); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void run_build(const char* command) { | ||||
|   regex err_re("(.*?):([0-9]+):([0-9]+):\\s*(.*?):\\s*(.*)"); | ||||
|   char buffer[BUF_MAX]; // BUF_MAX is a define already?
 | ||||
|   smatch err; | ||||
|   ofstream stats_out; | ||||
|   stats_out.open("stats.csv", ios::out | ios::app); | ||||
|   auto t = time(nullptr); | ||||
|   auto tm = *std::gmtime(&t); | ||||
| 
 | ||||
|   dbc::check(stats_out.good(), "Error opening stats.csv file."); | ||||
|   dbc::pre("simple test", [&]() { return stats_out.good(); }); | ||||
| 
 | ||||
|   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
 | ||||
| 
 | ||||
|     print("{}\n", line); | ||||
|     if(regex_match(line, err, err_re)) { | ||||
|       string file_name = err[1].str(); | ||||
|       string line = err[2].str(); | ||||
|       string col = err[3].str(); | ||||
|       string type = err[4].str(); | ||||
|       string message = err[5].str(); | ||||
| 
 | ||||
|       stats_out << put_time(&tm, "%FT%TZ"); | ||||
|       stats_out << format(",{},{},{},{},{}\n", file_name, line, col, type, message); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   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]; | ||||
| 
 | ||||
|     print("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(); | ||||
|     dbc::check(listener != nullptr, "Failed to create listener."); | ||||
| 
 | ||||
|     print("Watching directory {} for changes...\n", git_path); | ||||
|     efsw::WatchID wid = fileWatcher->addWatch(git_path, listener, true); | ||||
| 
 | ||||
|     while(true) { | ||||
|       fileWatcher->watch(); | ||||
| 
 | ||||
|       if(listener->changes) { | ||||
|         sleep(1); | ||||
|         list_git_changes(repo); | ||||
|         listener->reset_state(); | ||||
|         run_build(build_cmd); | ||||
|       } | ||||
| 
 | ||||
|       sleep(1); | ||||
|     } | ||||
| 
 | ||||
|     git_libgit2_shutdown(); | ||||
|   } catch(dbc::Error &err) { | ||||
|     print("ERROR: {}\n", err.message); | ||||
|     if(repo != nullptr) git_repository_free(repo); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   git_libgit2_shutdown(); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zed A. Shaw
						Zed A. Shaw