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
|
*.exe
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
/version.hpp
|
||||||
|
|
|
@ -1,2 +1,91 @@
|
||||||
# CMake configuration for demo project
|
# CMake configuration for demo project
|
||||||
cmake_minimum_required(VERSION 3.16)
|
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
Reference in a new issue