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
Reference in a new issue