Merge branch 'develop'

This commit is contained in:
Tobias Schmidl 2022-10-06 11:24:21 +02:00
commit 126f0518c0
11 changed files with 408 additions and 0 deletions

5
.clang-format Normal file
View file

@ -0,0 +1,5 @@
---
BasedOnStyle: Mozilla
IndentWidth: 4
...
# vim: set filetype=yaml:

12
.cmake-format.yaml Normal file
View 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
View file

@ -66,3 +66,4 @@ tags
*.exe
*.out
*.app
/version.hpp

View file

@ -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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
cmakelang[yaml]~=0.6.13

66
test.cpp Normal file
View 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
View 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@"