Merge branch 'develop'
This commit is contained in:
		
						commit
						126f0518c0
					
				
					 11 changed files with 408 additions and 0 deletions
				
			
		
							
								
								
									
										5
									
								
								.clang-format
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.clang-format
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| BasedOnStyle: Mozilla | ||||
| IndentWidth: 4 | ||||
| ... | ||||
| # vim: set filetype=yaml: | ||||
							
								
								
									
										12
									
								
								.cmake-format.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.cmake-format.yaml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| format: | ||||
|   line_width: 120 | ||||
|   tab_size: 4 | ||||
|   use_tabchars: true | ||||
|   fractional_tab_policy: round-up | ||||
|   max_subgroups_hwrap: 2 | ||||
|   max_pargs_hwrap: 3 | ||||
|   dangle_parens: true | ||||
|   dangle_align: prefix | ||||
|   min_prefix_chars: 0 | ||||
|   max_prefix_chars: 16 | ||||
|   keyword_case: upper | ||||
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -66,3 +66,4 @@ tags | |||
| *.exe | ||||
| *.out | ||||
| *.app | ||||
| /version.hpp | ||||
|  |  | |||
|  | @ -1,2 +1,91 @@ | |||
| # CMake configuration for demo project | ||||
| cmake_minimum_required(VERSION 3.16) | ||||
| set(CMAKE_CXX_STANDARD 17) | ||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
| set(CMAKE_CXX_CLANG_TIDY clang-tidy) | ||||
| 
 | ||||
| include(ProcessorCount) | ||||
| ProcessorCount(CPU_COUNT) | ||||
| if(CPU_COUNT EQUAL 0) | ||||
| 	set(CPU_COUNT 4) | ||||
| endif() | ||||
| message(STATUS "Counted ${CPU_COUNT} cores") | ||||
| set(CTEST_BUILD_FLAGS -j${CPU_COUNT}) | ||||
| set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${CPU_COUNT}) | ||||
| 
 | ||||
| execute_process( | ||||
| 	COMMAND git describe --tags --dirty --always | ||||
| 	WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
| 	OUTPUT_VARIABLE VERSION_STRING | ||||
| 	OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
| ) | ||||
| 
 | ||||
| string( | ||||
| 	REGEX | ||||
| 	REPLACE "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" | ||||
| 			"\\1.\\2.\\3" | ||||
| 			MODIFIED_VERSION_STRING | ||||
| 			"${VERSION_STRING}" | ||||
| ) | ||||
| project( | ||||
| 	collector | ||||
| 	VERSION ${MODIFIED_VERSION_STRING} | ||||
| 	LANGUAGES CXX | ||||
| ) | ||||
| 
 | ||||
| include(FetchContent) | ||||
| set(FETCHCONTENT_QUIET FALSE) | ||||
| set(BOOST_ENABLE_CMAKE ON) | ||||
| 
 | ||||
| FetchContent_Declare( | ||||
| 	boostorg | ||||
| 	GIT_REPOSITORY https://github.com/boostorg/boost.git | ||||
| 	GIT_TAG boost-1.80.0 | ||||
| 	GIT_PROGRESS TRUE | ||||
| 	GIT_CONFIG fetch.parallel=${CPU_COUNT} submodule.fetchJobs=${CPU_COUNT} | ||||
| 	GIT_SHALLOW TRUE | ||||
| ) | ||||
| 
 | ||||
| FetchContent_Declare( | ||||
| 	dir_monitor | ||||
| 	GIT_REPOSITORY https://github.com/schtobia/dir_monitor.git | ||||
| 	GIT_TAG master | ||||
| 	GIT_PROGRESS TRUE | ||||
| 	GIT_SHALLOW TRUE | ||||
| ) | ||||
| 
 | ||||
| FetchContent_Populate(boostorg) | ||||
| add_subdirectory(${boostorg_SOURCE_DIR} ${boostorg_BINARY_DIR}) | ||||
| 
 | ||||
| FetchContent_MakeAvailable(dir_monitor) | ||||
| 
 | ||||
| enable_testing() | ||||
| 
 | ||||
| configure_file(version.hpp.in ${PROJECT_SOURCE_DIR}/version.hpp) | ||||
| 
 | ||||
| add_executable(${PROJECT_NAME}_test test.cpp) | ||||
| target_compile_options( | ||||
| 	${PROJECT_NAME}_test | ||||
| 	PUBLIC -Wall | ||||
| 			-Wextra | ||||
| 			-Wshadow | ||||
| 			-Wnon-virtual-dtor | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries( | ||||
| 	${PROJECT_NAME}_test | ||||
| 	PRIVATE Boost::filesystem | ||||
| 			Boost::system | ||||
| 			Boost::unit_test_framework | ||||
| 			dir_monitor | ||||
| ) | ||||
| 
 | ||||
| add_test(NAME test1 COMMAND $[PROJECT_NAME}_test) | ||||
| add_executable(${PROJECT_NAME} main.cpp) | ||||
| target_link_libraries( | ||||
| 	${PROJECT_NAME} | ||||
| 	PRIVATE Boost::filesystem | ||||
| 			Boost::system | ||||
| 			Boost::program_options | ||||
| 			dir_monitor | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										21
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2022 Tobias Schmidl | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										56
									
								
								collector.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								collector.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| /**
 | ||||
|  * @file collector.hpp | ||||
|  *  Collects file events and acts upon them | ||||
|  * | ||||
|  * @author Tobias Schmidl | ||||
|  * @copyright Copyright © 2022, Tobias Schmidl | ||||
|  * SPDX-License-Identifier: MIT | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| #include "monitor.hpp" | ||||
| #include <filesystem> | ||||
| #include <regex> | ||||
| 
 | ||||
| // for system()
 | ||||
| #include <cstdlib> | ||||
| #include <string> | ||||
| 
 | ||||
| constexpr const char* FILTER = "^Core\\.[^.][^.]*\\..*\\.lz4"; | ||||
| 
 | ||||
| namespace collector::collector { | ||||
| 
 | ||||
| class Collector | ||||
| { | ||||
|     monitor::Monitor _monitor; | ||||
|     std::filesystem::path _target_file; | ||||
| 
 | ||||
|   public: | ||||
|     Collector(boost::asio::io_service& service, | ||||
|               std::filesystem::path&& root_path, | ||||
|               std::filesystem::path&& target_file) | ||||
|       : _monitor(service, std::move(root_path)) | ||||
|       , _target_file(std::move(target_file)) | ||||
|     { | ||||
|     } | ||||
|     Collector(boost::asio::io_service& service, | ||||
|               const std::filesystem::path& root_path, | ||||
|               const std::filesystem::path& target_file) | ||||
|       : _monitor(service, root_path) | ||||
|       , _target_file(target_file) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     bool operator()() | ||||
|     { | ||||
|         const auto& fs_event = | ||||
|           _monitor.watch(std::regex(FILTER), | ||||
|                          boost::asio::dir_monitor_event::event_type::added); | ||||
|         // big fugly hack
 | ||||
|         std::string call_command = | ||||
|           std::string("/usr/bin/tar cvf ") + _target_file.generic_string() + | ||||
|           std::string(" ") + _monitor.get_root_path().generic_string(); | ||||
|         return system(call_command.c_str()) == 0; | ||||
|     } | ||||
| }; | ||||
| } | ||||
							
								
								
									
										62
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| /**
 | ||||
|  * @file main.cpp | ||||
|  *  The main executable | ||||
|  * | ||||
|  * @author Tobias Schmidl | ||||
|  * @copyright Copyright © 2022, Tobias Schmidl | ||||
|  * SPDX-License-Identifier: MIT | ||||
|  */ | ||||
| 
 | ||||
| #include "collector.hpp" | ||||
| #include "monitor.hpp" | ||||
| #include "version.hpp" | ||||
| #include <boost/program_options.hpp> | ||||
| #include <filesystem> | ||||
| #include <iostream> | ||||
| 
 | ||||
| using namespace collector::monitor; | ||||
| using namespace collector::collector; | ||||
| using namespace boost::program_options; | ||||
| 
 | ||||
| int | ||||
| main(int argc, const char* argv[]) | ||||
| { | ||||
|     std::cerr << argv[0] << " Version v" << VERSION << "\n"; | ||||
|     options_description description{ "Options" }; | ||||
|     description.add_options()("help,h", "Help screen")( | ||||
|       "input_dir,i", value<std::string>()->required(), "Input Directory")( | ||||
|       "output_file,o", value<std::string>()->required(), "Output Tarball"); | ||||
|     variables_map vm; | ||||
|     try { | ||||
|         store(parse_command_line(argc, argv, description), vm); | ||||
|         notify(vm); | ||||
|     } catch (std::exception& err) { | ||||
|         std::cerr << "Error: " << err.what() << "\n"; | ||||
|         std::cerr << description << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     std::filesystem::path input_dir, output_file; | ||||
|     if (vm.count("help")) { | ||||
|         std::cerr << description << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
|     if (vm.count("input_dir")) { | ||||
|         input_dir = vm["input_dir"].as<std::string>(); | ||||
|         if (!std::filesystem::is_directory(input_dir)) { | ||||
|             std::cerr << input_dir << " is not a valid directory." << std::endl; | ||||
|             return 1; | ||||
|         } else | ||||
|             std::cerr << "input dir: " << input_dir << "\n"; | ||||
|     } | ||||
|     if (vm.count("output_file")) { | ||||
|         output_file = vm["output_file"].as<std::string>(); | ||||
|         std::cout << "output file: " << output_file << "\n"; | ||||
|     } | ||||
| 
 | ||||
|     boost::asio::io_service service; | ||||
| 
 | ||||
|     Collector collector(service, input_dir, output_file); | ||||
|     return (collector() && std::filesystem::is_regular_file(output_file)) ? 0 | ||||
|                                                                           : 2; | ||||
| } | ||||
							
								
								
									
										90
									
								
								monitor.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								monitor.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| /**
 | ||||
|  * @file monitor.hpp | ||||
|  *  A dir_monitor wrapper for specific paths | ||||
|  * | ||||
|  * @author Tobias Schmidl | ||||
|  * @copyright Copyright © 2022, Tobias Schmidl | ||||
|  * SPDX-License-Identifier: MIT | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| #include <dir_monitor/dir_monitor.hpp> | ||||
| #include <filesystem> | ||||
| #include <regex> | ||||
| 
 | ||||
| namespace collector::monitor { | ||||
| 
 | ||||
| class Monitor | ||||
| { | ||||
|   private: | ||||
|     boost::asio::dir_monitor _monitor; | ||||
|     std::filesystem::path _root_path; | ||||
| 
 | ||||
|   public: | ||||
|     explicit Monitor(boost::asio::io_service& io_service, | ||||
|                      std::filesystem::path&& root_path) | ||||
|       : _monitor(io_service) | ||||
|       , _root_path(std::move(root_path)) | ||||
|     { | ||||
|         _monitor.add_directory(_root_path); | ||||
|         for (const auto& dir_entry : | ||||
|              std::filesystem::recursive_directory_iterator(_root_path)) { | ||||
|             if (dir_entry.is_directory()) | ||||
|                 _monitor.add_directory(dir_entry.path()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     explicit Monitor(boost::asio::io_service& io_service, | ||||
|                      const std::filesystem::path& root_path) | ||||
|       : _monitor(io_service) | ||||
|       , _root_path(root_path) | ||||
|     { | ||||
|         _monitor.add_directory(_root_path); | ||||
|         for (const auto& dir_entry : | ||||
|              std::filesystem::recursive_directory_iterator(_root_path)) { | ||||
|             if (dir_entry.is_directory()) | ||||
|                 _monitor.add_directory(dir_entry.path()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * watches any for any event that matches the given search_pattern | ||||
|      */ | ||||
|     boost::asio::dir_monitor_event watch(const std::regex& search_pattern) | ||||
|     { | ||||
|         boost::asio::dir_monitor_event monitored_event; | ||||
|         do { | ||||
|             monitored_event = _monitor.monitor(); | ||||
|         } while (!std::regex_match( | ||||
|           monitored_event.path.filename().generic_string(), search_pattern)); | ||||
|         return monitored_event; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * watches any for the specified event_type that also matches the given | ||||
|      * search_pattern | ||||
|      */ | ||||
|     boost::asio::dir_monitor_event watch( | ||||
|       const std::regex& search_pattern, | ||||
|       const boost::asio::dir_monitor_event::event_type event_type) | ||||
|     { | ||||
|         boost::asio::dir_monitor_event monitored_event; | ||||
|         do { | ||||
|             monitored_event = _monitor.monitor(); | ||||
|         } while ( | ||||
|           !std::regex_match(monitored_event.path.filename().generic_string(), | ||||
|                             search_pattern) || | ||||
|           monitored_event.type != event_type); | ||||
|         return monitored_event; | ||||
|     } | ||||
| 
 | ||||
|     const auto& get_root_path() const { return _root_path; } | ||||
|     virtual ~Monitor() = default; | ||||
| 
 | ||||
|     Monitor() = delete; | ||||
|     Monitor(Monitor&& other) = delete; | ||||
|     Monitor(const Monitor& other) = delete; | ||||
|     Monitor& operator=(Monitor&& other) = delete; | ||||
|     Monitor& operator=(const Monitor& other) = delete; | ||||
| }; | ||||
| } | ||||
							
								
								
									
										1
									
								
								requirements.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								requirements.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| cmakelang[yaml]~=0.6.13 | ||||
							
								
								
									
										66
									
								
								test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								test.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| /**
 | ||||
|  * @file test.cpp | ||||
|  *  The unit test executable | ||||
|  * | ||||
|  * @author Tobias Schmidl | ||||
|  * @copyright Copyright © 2022, Tobias Schmidl | ||||
|  * SPDX-License-Identifier: MIT | ||||
|  */ | ||||
| 
 | ||||
| #include "collector.hpp" | ||||
| #include "monitor.hpp" | ||||
| #include "version.hpp" | ||||
| #define BOOST_TEST_MODULE Collector test | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <chrono> | ||||
| #include <fstream> | ||||
| #include <future> | ||||
| #include <thread> | ||||
| 
 | ||||
| using namespace collector::monitor; | ||||
| using namespace collector::collector; | ||||
| using namespace std::chrono_literals; | ||||
| 
 | ||||
| boost::asio::io_service service; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(monitor_test) | ||||
| { | ||||
|     BOOST_TEST_MESSAGE("Test version " << VERSION); | ||||
|     const std::filesystem::path test_file{ "test_file" }; | ||||
|     std::filesystem::remove(test_file); | ||||
|     const auto create_file_result = std::async([&test_file]() { | ||||
|         std::this_thread::sleep_for(2s); | ||||
|         std::ofstream{ test_file }; | ||||
|     }); | ||||
|     Monitor monitor(service, std::filesystem::current_path()); | ||||
|     const auto& watch_result = | ||||
|       monitor.watch(std::regex(test_file.generic_string()), | ||||
|                     boost::asio::dir_monitor_event::event_type::added); | ||||
|     BOOST_TEST(std::filesystem::equivalent(test_file, | ||||
|                                            watch_result.path.generic_string())); | ||||
|     std::filesystem::remove(test_file); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(collector_test) | ||||
| { | ||||
|     BOOST_TEST_MESSAGE("Test version " << VERSION); | ||||
|     const std::filesystem::path target_file{ "test.tar" }, | ||||
|       test_input_dir{ "test_input" }; | ||||
|     std::filesystem::remove(target_file); | ||||
|     std::filesystem::remove_all(test_input_dir); | ||||
|     std::filesystem::create_directory(test_input_dir); | ||||
|     const auto create_file_result = std::async([&test_input_dir]() { | ||||
|         std::this_thread::sleep_for(5s); | ||||
|         std::ofstream test_file{ test_input_dir / "should_be_in_it" }; | ||||
|         test_file << "Hello World." << std::endl; | ||||
|         test_file.flush(); | ||||
| 
 | ||||
|         std::ofstream{ test_input_dir / "Core.TEST.00.lz4" }; | ||||
|         std::ofstream{ test_input_dir / "might_not_be_in_it" }; | ||||
|     }); | ||||
|     Collector collector(service, test_input_dir, target_file); | ||||
|     BOOST_TEST(collector()); | ||||
|     BOOST_TEST(std::filesystem::is_regular_file(target_file)); | ||||
|     std::filesystem::remove(target_file); | ||||
|     std::filesystem::remove_all(test_input_dir); | ||||
| } | ||||
							
								
								
									
										5
									
								
								version.hpp.in
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								version.hpp.in
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| #define VERSION_MAJOR @PROJECT_VERSION_MAJOR@ | ||||
| #define VERSION_MINOR @PROJECT_VERSION_MINOR@ | ||||
| #define VERSION_PATCH @PROJECT_VERSION_PATCH@ | ||||
| #define VERSION_TWEAK @PROJECT_VERSION_TWEAK@ | ||||
| #define VERSION "@PROJECT_VERSION@" | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue