Compare commits
5 Commits
9c01297069
...
75ae416c52
Author | SHA1 | Date | |
---|---|---|---|
75ae416c52 | |||
17c39cdc6a | |||
9c9e1c9828 | |||
c8205adb50 | |||
ab89424ad1 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -55,7 +55,7 @@ bld/
|
||||
[Bb]uild/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
cmake-build-debug
|
||||
cmake-build-debug*
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
|
@ -7,7 +7,11 @@ COPY . ./
|
||||
RUN mkdir build && cd build && ../cbuildrel
|
||||
|
||||
FROM alpine:latest as run
|
||||
|
||||
RUN apk add libstdc++
|
||||
|
||||
COPY --from=build /kc/build/kc /kc/kc
|
||||
RUN mkdir /kc/log
|
||||
|
||||
WORKDIR /kc
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
task/current_tasks.cpp
|
||||
net/ntfy.cpp
|
||||
net/http.cpp
|
||||
# image/img.cpp
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
@ -27,7 +26,27 @@ FetchContent_MakeAvailable(Boost)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
#find_package( OpenCV REQUIRED )
|
||||
#include_directories( ${OpenCV_INCLUDE_DIRS} )
|
||||
if(OPENCV)
|
||||
add_compile_definitions(WITH_OPENCV)
|
||||
find_package( OpenCV REQUIRED )
|
||||
include_directories( ${OpenCV_INCLUDE_DIRS} )
|
||||
target_sources(kc PRIVATE image/img.cpp)
|
||||
endif()
|
||||
|
||||
target_link_libraries(kc PRIVATE Boost::program_options Boost::log Boost::date_time Boost::filesystem Boost::system Boost::thread Boost::log_setup Boost::chrono Boost::atomic Boost::asio Boost::beast Boost::json Boost::algorithm ${OPENSSL_LIBRARIES} ${OpenCV_LIBS})
|
||||
target_link_libraries(kc PRIVATE
|
||||
Boost::program_options
|
||||
Boost::log
|
||||
Boost::date_time
|
||||
Boost::filesystem
|
||||
Boost::system
|
||||
Boost::thread
|
||||
Boost::log_setup
|
||||
Boost::chrono
|
||||
Boost::atomic
|
||||
Boost::asio
|
||||
Boost::beast
|
||||
Boost::json
|
||||
Boost::algorithm
|
||||
${OPENSSL_LIBRARIES}
|
||||
${OpenCV_LIBS}
|
||||
)
|
@ -5,12 +5,16 @@
|
||||
#include "config.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
#if __cpp_lib_execution //checking to see if the <execution> header is there
|
||||
#include <execution>
|
||||
#endif
|
||||
|
||||
namespace kc {
|
||||
|
||||
AppContext::AppContext(): config_loaded(false) {
|
||||
}
|
||||
|
||||
void AppContext::load_config(int argc, const char *argv[])
|
||||
void AppContext::load_config(const int argc, const char *argv[])
|
||||
{
|
||||
config = init_config(argc, argv);
|
||||
config_loaded = true;
|
||||
@ -22,17 +26,31 @@ void AppContext::load_and_parse_cache() {
|
||||
|
||||
void AppContext::load_and_parse_cache(ParseOperations operations)
|
||||
{
|
||||
if (!config->contains("path")) {
|
||||
print_and_log_error("No paths provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto env_paths = (*config)["path"].as<std::vector<std::string>>();
|
||||
|
||||
for (const auto& env_path : env_paths) {
|
||||
#ifdef __cpp_lib_execution
|
||||
std::mutex m;
|
||||
std::for_each(std::execution::par, env_paths.begin(), env_paths.end(), [this, &operations, &m](const std::string &env_path)
|
||||
#else
|
||||
std::ranges::for_each(env_paths, [this, &operations](const std::string &env_path)
|
||||
#endif
|
||||
{
|
||||
print_and_log("Loading knowledge base from " + env_path);
|
||||
|
||||
auto file_cache = std::make_shared<kc::FileContextCache>();
|
||||
const auto file_cache = std::make_shared<kc::FileContextCache>();
|
||||
file_cache->load(env_path);
|
||||
file_cache->parse_all(operations);
|
||||
|
||||
#ifdef __cpp_lib_execution
|
||||
std::lock_guard<std::mutex> lock{m};
|
||||
#endif
|
||||
file_caches.push_back(file_cache);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string AppContext::command() const {
|
||||
@ -40,10 +58,7 @@ std::string AppContext::command() const {
|
||||
{
|
||||
return (*config)["command"].as<std::string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "const.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
po::options_description get_current_tasks_options() {
|
||||
po::options_description options("Current Tasks");
|
||||
@ -15,6 +16,7 @@ po::options_description get_current_tasks_options() {
|
||||
(CONFIG_HOST.c_str(), po::value<std::string>(), "ntfy hostname")
|
||||
(CONFIG_TOPIC.c_str(), po::value<std::string>(), "ntfy topic name")
|
||||
(CONFIG_TITLE.c_str(), po::value<std::string>(), "title for notifications")
|
||||
(CONFIG_TAGS.c_str(), po::value<std::vector<std::string>>(), "tags to add to notification")
|
||||
;
|
||||
|
||||
return options;
|
||||
@ -28,6 +30,7 @@ std::shared_ptr<po::variables_map> init_config(int argc, const char *argv[])
|
||||
("help,h", "produce help message")
|
||||
("path,p", po::value<std::vector<std::string>>(), "set root path of knowledge base")
|
||||
("config", po::value<std::string>()->default_value("kc.ini"), "config file location")
|
||||
("logpath", po::value<std::string>()->default_value("."), "log folder location")
|
||||
;
|
||||
|
||||
po::options_description hidden_general("Hidden");
|
||||
@ -75,10 +78,10 @@ std::shared_ptr<po::variables_map> init_config(int argc, const char *argv[])
|
||||
if (vm->contains("config"))
|
||||
{
|
||||
auto config_path = (*vm)["config"].as<std::string>();
|
||||
BOOST_LOG_TRIVIAL(info) << "Attempting file config load for " << config_path;
|
||||
// BOOST_LOG_TRIVIAL(info) << "Attempting file config load for " << config_path;
|
||||
|
||||
if (std::ifstream ifs{config_path.c_str()}) {
|
||||
BOOST_LOG_TRIVIAL(info) << "File opened, loading...";
|
||||
// BOOST_LOG_TRIVIAL(info) << "File opened, loading...";
|
||||
po::store(po::parse_config_file(ifs, config_file_options), *vm);
|
||||
}
|
||||
}
|
||||
@ -88,9 +91,7 @@ std::shared_ptr<po::variables_map> init_config(int argc, const char *argv[])
|
||||
|
||||
if (vm->count("command") == 1)
|
||||
{
|
||||
auto command = (*vm)["command"].as<std::string>();
|
||||
|
||||
if (command == CMD_CURRENT_TASKS) {
|
||||
if (auto command = (*vm)["command"].as<std::string>(); command == CMD_CURRENT_TASKS) {
|
||||
std::cout << visible_general << std::endl << current_tasks_options;
|
||||
}
|
||||
}
|
||||
@ -107,7 +108,7 @@ std::shared_ptr<po::variables_map> init_config(int argc, const char *argv[])
|
||||
}
|
||||
catch (const po::error &ex)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << ex.what();
|
||||
std::cout << ex.what() << std::endl;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ static const std::string CMD_VALIDATE_TASKS = "validate";
|
||||
static const std::string CMD_IMG_TASKS = "img";
|
||||
static const std::string CMD_PRINT_TASKS = "print";
|
||||
static const std::string CMD_CURRENT_TASKS = "current";
|
||||
static const std::string CMD_NET_TASKS = "net";
|
||||
|
||||
|
||||
///////////////
|
||||
@ -21,6 +20,7 @@ static const std::string CONFIG_NOTIFY = "notify";
|
||||
static const std::string CONFIG_HOST = "host";
|
||||
static const std::string CONFIG_TOPIC = "topic";
|
||||
static const std::string CONFIG_TITLE = "title";
|
||||
static const std::string CONFIG_TAGS = "tag";
|
||||
|
||||
|
||||
///////////////
|
||||
|
@ -15,16 +15,21 @@ bool FileEntry::content_loaded() const
|
||||
return loaded;
|
||||
}
|
||||
|
||||
std::string FileEntry::load_content()
|
||||
std::vector<std::string> FileEntry::load_content()
|
||||
{
|
||||
std::ifstream ifs(file_entry.path());
|
||||
file_content.assign( (std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()) );
|
||||
|
||||
for (std::string line; std::getline(ifs, line);)
|
||||
{
|
||||
file_content.emplace_back(line);
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
|
||||
return file_content;
|
||||
}
|
||||
|
||||
std::string FileEntry::get_content() const
|
||||
std::vector<std::string> FileEntry::get_content() const
|
||||
{
|
||||
return file_content;
|
||||
}
|
||||
|
@ -18,13 +18,13 @@ class FileEntry {
|
||||
fs::path relative_path;
|
||||
|
||||
[[nodiscard]] bool content_loaded() const;
|
||||
std::string load_content();
|
||||
[[nodiscard]] std::string get_content() const;
|
||||
std::vector<std::string> load_content();
|
||||
[[nodiscard]] std::vector<std::string> get_content() const;
|
||||
void clear_content();
|
||||
|
||||
private:
|
||||
|
||||
std::string file_content;
|
||||
std::vector<std::string> file_content;
|
||||
bool loaded;
|
||||
};
|
||||
|
||||
|
@ -5,12 +5,11 @@
|
||||
|
||||
static const std::string exclusions[] = {".git", ".obsidian"};
|
||||
|
||||
std::vector<std::shared_ptr<kc::FileEntry>> kc::walk_dir(const std::string dir)
|
||||
std::vector<std::shared_ptr<kc::FileEntry>> kc::walk_dir(const std::string &dir)
|
||||
{
|
||||
auto matched = std::vector<std::shared_ptr<kc::FileEntry>>();
|
||||
const auto base_path = fs::path(dir);
|
||||
|
||||
for (auto const& dir_entry : fs::recursive_directory_iterator(base_path))
|
||||
for (const auto base_path = fs::path(dir); auto const& dir_entry : fs::recursive_directory_iterator(base_path))
|
||||
{
|
||||
if (dir_entry.is_directory()) continue;
|
||||
|
||||
|
@ -11,6 +11,6 @@ namespace fs = std::filesystem;
|
||||
|
||||
namespace kc {
|
||||
|
||||
std::vector<std::shared_ptr<kc::FileEntry>> walk_dir(std::string dir);
|
||||
std::vector<std::shared_ptr<kc::FileEntry>> walk_dir(const std::string &dir);
|
||||
|
||||
}
|
@ -1,18 +1,22 @@
|
||||
#include "logging.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace logging = boost::log;
|
||||
namespace src = boost::log::sources;
|
||||
namespace sinks = boost::log::sinks;
|
||||
namespace keywords = boost::log::keywords;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
void init_logging()
|
||||
void init_logging(const std::string &log_path)
|
||||
{
|
||||
logging::register_simple_formatter_factory<logging::trivial::severity_level, char>("Severity");
|
||||
|
||||
auto log_file = std::string(fs::path(log_path) / fs::path("kc_%N.log"));
|
||||
|
||||
logging::add_file_log
|
||||
(
|
||||
keywords::file_name = "kc_%N.log",
|
||||
keywords::file_name = log_file,
|
||||
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
|
||||
keywords::format = "[%TimeStamp%] [%ThreadID%] [%Severity%] %Message%",
|
||||
keywords::open_mode = std::ios::app
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
|
||||
void init_logging();
|
||||
void init_logging(const std::string &log_path);
|
||||
|
||||
inline void print_and_log(std::string log_line)
|
||||
{
|
||||
|
115
src/main.cpp
115
src/main.cpp
@ -3,78 +3,84 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#include "const.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "config.hpp"
|
||||
#include "appcontext.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "net/http.hpp"
|
||||
#include "net/ntfy.hpp"
|
||||
#include "parse/FileContextCache.hpp"
|
||||
#include "print/print.hpp"
|
||||
#include "task/current_tasks.hpp"
|
||||
#include "valid/link.hpp"
|
||||
//#include "image/img.hpp"
|
||||
|
||||
#ifdef WITH_OPENCV
|
||||
#include "image/img.hpp"
|
||||
#endif
|
||||
|
||||
void run_validate(const kc::AppContext &app_context);
|
||||
void run_img(const kc::AppContext &app_context);
|
||||
void run_print(const kc::AppContext &app_context);
|
||||
int run_current_tasks(const kc::AppContext &app_context);
|
||||
void run_test_net(const kc::AppContext &app_context);
|
||||
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
init_logging();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "================================";
|
||||
BOOST_LOG_TRIVIAL(info) << " kc";
|
||||
BOOST_LOG_TRIVIAL(info) << "================================";
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting up....";
|
||||
|
||||
kc::AppContext app_context;
|
||||
app_context.load_config(argc, argv);
|
||||
|
||||
if(app_context.config)
|
||||
{
|
||||
const auto command = app_context.command();
|
||||
if (!command.empty())
|
||||
{
|
||||
if (command == CMD_VALIDATE_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::LINKS);
|
||||
run_validate(app_context);
|
||||
}
|
||||
else if (command == CMD_IMG_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::IMAGES);
|
||||
run_img(app_context);
|
||||
}
|
||||
else if (command == CMD_PRINT_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache();
|
||||
run_print(app_context);
|
||||
}
|
||||
else if (command == CMD_CURRENT_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::TASKS);
|
||||
return run_current_tasks(app_context);
|
||||
}
|
||||
else if (command == CMD_NET_TASKS)
|
||||
{
|
||||
// app_context.load_and_parse_cache(kc::TASKS);
|
||||
run_test_net(app_context);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print_and_log_error("Command not found, exiting");
|
||||
return 1;
|
||||
}
|
||||
init_logging((*app_context.config)["logpath"].as<std::string>());
|
||||
|
||||
return 0;
|
||||
try {
|
||||
BOOST_LOG_TRIVIAL(info) << "================================";
|
||||
BOOST_LOG_TRIVIAL(info) << " kc";
|
||||
BOOST_LOG_TRIVIAL(info) << "================================";
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting up....";
|
||||
|
||||
#ifdef __cpp_lib_execution
|
||||
BOOST_LOG_TRIVIAL(debug) << "Compiled with parallel loops";
|
||||
#else
|
||||
BOOST_LOG_TRIVIAL(debug) << "Compiled WITHOUT parallel loops";
|
||||
#endif
|
||||
|
||||
if(app_context.config)
|
||||
{
|
||||
if (const auto command = app_context.command(); !command.empty())
|
||||
{
|
||||
if (command == CMD_VALIDATE_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::LINKS);
|
||||
run_validate(app_context);
|
||||
}
|
||||
#ifdef WITH_OPENCV
|
||||
else if (command == CMD_IMG_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::IMAGES);
|
||||
run_img(app_context);
|
||||
}
|
||||
#endif
|
||||
else if (command == CMD_PRINT_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache();
|
||||
run_print(app_context);
|
||||
}
|
||||
else if (command == CMD_CURRENT_TASKS)
|
||||
{
|
||||
app_context.load_and_parse_cache(kc::TASKS);
|
||||
return run_current_tasks(app_context);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print_and_log_error("Command not found, exiting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
print_and_log_error(std::format("Exception occurred - {}", e.what()));
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -91,11 +97,14 @@ void run_validate(const kc::AppContext &app_context)
|
||||
|
||||
void run_img(const kc::AppContext &app_context)
|
||||
{
|
||||
#ifdef WITH_OPENCV
|
||||
BOOST_LOG_TRIVIAL(info) << "Running \"Image Processing\" command";
|
||||
for(const auto& file_cache : app_context.file_caches) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Image processing in " << file_cache->get_root_path();
|
||||
// kc::image_proc(file_cache->get());
|
||||
kc::image_proc(file_cache->get());
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void run_print(const kc::AppContext &app_context)
|
||||
@ -110,10 +119,4 @@ int run_current_tasks(const kc::AppContext &app_context)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "Running \"Current Tasks\" command";
|
||||
return kc::current_tasks(app_context);
|
||||
}
|
||||
|
||||
void run_test_net(const kc::AppContext &app_context)
|
||||
{
|
||||
kc::notify("ntfy.sheep-ghoul.ts.net",
|
||||
kc::Notification("todo", "next test!"));
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <utility>
|
||||
|
||||
// https://www.boost.org/doc/libs/1_87_0/libs/beast/example/http/client/sync-ssl/http_client_sync_ssl.cpp
|
||||
|
||||
@ -38,11 +39,11 @@ void shutdown_stream(const std::shared_ptr<ssl::stream<beast::tcp_stream>> &stre
|
||||
}
|
||||
|
||||
void request(http::verb method, const std::string &host, std::string target, std::string body, std::unique_ptr<std::unordered_map<std::string, std::string>> headers) {
|
||||
request(method, host, target, 443, body, std::move(headers));
|
||||
request(std::move(method), std::move(host), std::move(target), 443, std::move(body), std::move(headers));
|
||||
}
|
||||
|
||||
void request(http::verb method, const std::string &host, std::string target, std::string body) {
|
||||
request(method, host, target, 443, body, nullptr);
|
||||
request(std::move(method), std::move(host), std::move(target), 443, std::move(body), nullptr);
|
||||
}
|
||||
|
||||
void request(http::verb method, const std::string &host, std::string target, int port, std::string body, std::unique_ptr<std::unordered_map<std::string, std::string>> headers) {
|
||||
@ -89,8 +90,8 @@ void request(http::verb method, const std::string &host, std::string target, int
|
||||
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
|
||||
if (headers) {
|
||||
for (auto const &kv : *headers) {
|
||||
req.set(kv.first, kv.second);
|
||||
for (const auto &[fst, snd] : *headers) {
|
||||
req.set(fst, snd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace kc {
|
||||
|
||||
constexpr std::string get_urgency_string(NotificationUrgency u){
|
||||
constexpr std::string get_urgency_string(const NotificationUrgency u){
|
||||
switch(u){
|
||||
case NotificationUrgency::MAX:
|
||||
return "max";
|
||||
@ -20,7 +20,7 @@ constexpr std::string get_urgency_string(NotificationUrgency u){
|
||||
return "default";
|
||||
}
|
||||
|
||||
void notify(std::string host, Notification notification)
|
||||
void notify(const std::string &host, const Notification ¬ification)
|
||||
{
|
||||
request(
|
||||
http::verb::post,
|
||||
|
@ -58,6 +58,6 @@ private:
|
||||
NotificationUrgency priority;
|
||||
};
|
||||
|
||||
void notify(std::string host, Notification notification);
|
||||
void notify(const std::string &host, const Notification ¬ification);
|
||||
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
#include "FileContext.hpp"
|
||||
|
||||
#include "../logging.hpp"
|
||||
|
||||
namespace kc {
|
||||
|
||||
FileContext::FileContext(std::shared_ptr<kc::FileEntry> entry)
|
||||
: file_entry(std::move(entry)), links_parsed(false) {
|
||||
}
|
||||
|
||||
constexpr int MAX_LINE_LENGTH = 3000;
|
||||
|
||||
void FileContext::parse()
|
||||
{
|
||||
if (!file_entry->content_loaded())
|
||||
@ -24,7 +28,7 @@ void FileContext::parse()
|
||||
parse_tasks();
|
||||
}
|
||||
|
||||
void FileContext::parse(ParseOperations operations)
|
||||
void FileContext::parse(const ParseOperations operations)
|
||||
{
|
||||
if (!file_entry->content_loaded())
|
||||
{
|
||||
@ -53,50 +57,86 @@ void FileContext::parse(ParseOperations operations)
|
||||
}
|
||||
|
||||
void FileContext::parse_links() {
|
||||
std::regex link_regex(MD_MD_LINK_REGEX);
|
||||
std::string file_content = file_entry->get_content();
|
||||
std::smatch link_match;
|
||||
while(std::regex_search(file_content, link_match, link_regex)) {
|
||||
const std::regex link_regex(MD_MD_LINK_REGEX, std::regex::optimize);
|
||||
const auto file_content = file_entry->get_content();
|
||||
|
||||
links.emplace_back(link_match.str());
|
||||
file_content = link_match.suffix();
|
||||
for (const auto& line : file_content) {
|
||||
if (line.length() < MAX_LINE_LENGTH) {
|
||||
std::string line_content = line;
|
||||
std::smatch link_match;
|
||||
while(std::regex_search(line_content, link_match, link_regex)) {
|
||||
|
||||
links.emplace_back(link_match.str());
|
||||
line_content = link_match.suffix();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Skipping line because too long: " << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileContext::parse_images() {
|
||||
std::regex image_regex(MD_IMAGE_LINK_REGEX);
|
||||
std::string file_content = file_entry->get_content();
|
||||
std::smatch image_match;
|
||||
while(std::regex_search(file_content, image_match, image_regex)) {
|
||||
const std::regex image_regex(MD_IMAGE_LINK_REGEX, std::regex::optimize);
|
||||
const auto file_content = file_entry->get_content();
|
||||
|
||||
images.emplace_back(image_match.str());
|
||||
file_content = image_match.suffix();
|
||||
for (const auto& line : file_content) {
|
||||
if (line.length() < MAX_LINE_LENGTH) {
|
||||
std::string line_content = line;
|
||||
std::smatch image_match;
|
||||
while(std::regex_search(line_content, image_match, image_regex)) {
|
||||
|
||||
images.emplace_back(image_match.str());
|
||||
line_content = image_match.suffix();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Skipping line because too long: " << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileContext::parse_tags() {
|
||||
#if __APPLE__
|
||||
std::regex tag_regex(MD_TAG_REGEX, std::regex::multiline);
|
||||
std::regex tag_regex(MD_TAG_REGEX, std::regex::multiline | std::regex::optimize);
|
||||
#else
|
||||
std::regex tag_regex(MD_TAG_REGEX);
|
||||
std::regex tag_regex(MD_TAG_REGEX, std::regex::optimize);
|
||||
#endif
|
||||
std::string file_content = file_entry->get_content();
|
||||
std::smatch tag_match;
|
||||
while(std::regex_search(file_content, tag_match, tag_regex)) {
|
||||
const auto file_content = file_entry->get_content();
|
||||
|
||||
tags.push_back(tag_match.str().substr(1));
|
||||
file_content = tag_match.suffix();
|
||||
for (const auto& line : file_content) {
|
||||
if (line.length() < MAX_LINE_LENGTH) {
|
||||
std::string line_content = line;
|
||||
std::smatch tag_match;
|
||||
while(std::regex_search(line_content, tag_match, tag_regex)) {
|
||||
|
||||
tags.push_back(tag_match.str().substr(1));
|
||||
line_content = tag_match.suffix();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Skipping line because too long: " << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileContext::parse_tasks() {
|
||||
std::regex task_regex(TASK_REGEX);
|
||||
std::string file_content = file_entry->get_content();
|
||||
std::smatch task_match;
|
||||
while(std::regex_search(file_content, task_match, task_regex)) {
|
||||
const std::regex task_regex(TASK_REGEX, std::regex::optimize);
|
||||
const auto file_content = file_entry->get_content();
|
||||
|
||||
tasks.emplace_back(task_match[2], task_match[1], task_match[3]);
|
||||
file_content = task_match.suffix();
|
||||
for (const auto& line : file_content) {
|
||||
if (line.length() < MAX_LINE_LENGTH) {
|
||||
std::string line_content = line;
|
||||
std::smatch task_match;
|
||||
while(std::regex_search(line_content, task_match, task_regex)) {
|
||||
|
||||
tasks.emplace_back(task_match[2], task_match[1], task_match[3]);
|
||||
line_content = task_match.suffix();
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Skipping line because too long: " << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,4 +145,4 @@ std::filesystem::path FileContext::abs_path(const kc::Link &link) const {
|
||||
return file_entry->file_entry.path().parent_path() / fs::path(link.link);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class FileContext {
|
||||
|
||||
void parse();
|
||||
void parse(ParseOperations operations);
|
||||
std::filesystem::path abs_path(const kc::Link &link) const;
|
||||
[[nodiscard]] std::filesystem::path abs_path(const kc::Link &link) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
#include "FileContextCache.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if __cpp_lib_execution //checking to see if the <execution> header is there
|
||||
#include <execution>
|
||||
#endif
|
||||
|
||||
#include "../fs/fs.hpp"
|
||||
#include "../logging.hpp"
|
||||
@ -36,12 +39,12 @@ void FileContextCache::parse_all()
|
||||
void FileContextCache::parse_all(ParseOperations operations) {
|
||||
tag_map.clear();
|
||||
|
||||
#if __APPLE__
|
||||
std::for_each(file_contexts.begin(), file_contexts.end(), [this, &operations](std::shared_ptr<kc::FileContext> &context)
|
||||
#ifdef __cpp_lib_execution
|
||||
std::mutex m;
|
||||
std::for_each(std::execution::par, file_contexts.begin(), file_contexts.end(), [this, &operations, &m](std::shared_ptr<kc::FileContext> &context)
|
||||
#else
|
||||
std::for_each(std::execution::par_unseq, file_contexts.begin(), file_contexts.end(), [this, &operations](std::shared_ptr<kc::FileContext> &context)
|
||||
std::ranges::for_each(file_contexts, [this, &operations](const std::shared_ptr<kc::FileContext> &context)
|
||||
#endif
|
||||
|
||||
{
|
||||
if (context->file_entry->relative_path.extension() == ".md")
|
||||
{
|
||||
@ -49,6 +52,9 @@ void FileContextCache::parse_all(ParseOperations operations) {
|
||||
|
||||
if (!context->tags.empty())
|
||||
{
|
||||
#ifdef __cpp_lib_execution
|
||||
std::lock_guard<std::mutex> lock{m};
|
||||
#endif
|
||||
for (const auto& tag : context->tags)
|
||||
{
|
||||
tag_map[tag].push_back(context->file_entry);
|
||||
|
@ -12,7 +12,7 @@ namespace kc {
|
||||
|
||||
void print_file(const std::vector<std::shared_ptr<kc::FileContext>> &contexts)
|
||||
{
|
||||
auto date = day_clock::local_day();
|
||||
const auto date = day_clock::local_day();
|
||||
|
||||
for (const auto &entry : contexts) {
|
||||
|
||||
|
@ -19,7 +19,7 @@ std::string get_notification_content(const std::vector<Task>& tasks) {
|
||||
|
||||
int current_tasks(const kc::AppContext &app_context)
|
||||
{
|
||||
auto date = day_clock::local_day();
|
||||
const auto date = day_clock::local_day();
|
||||
std::vector<Task> tasks;
|
||||
|
||||
for(const auto& file_cache : app_context.file_caches) {
|
||||
@ -33,7 +33,7 @@ int current_tasks(const kc::AppContext &app_context)
|
||||
}
|
||||
}
|
||||
|
||||
std::ranges::sort(tasks, [](Task a, Task b)
|
||||
std::ranges::sort(tasks, [](const Task &a, const Task &b)
|
||||
{
|
||||
return a.get_due_date() < b.get_due_date();
|
||||
});
|
||||
@ -42,7 +42,9 @@ int current_tasks(const kc::AppContext &app_context)
|
||||
std::cout << task.get_content() << " (" << task.get_due_date() << ")" << std::endl;
|
||||
}
|
||||
|
||||
if (app_context.config->contains(CONFIG_NOTIFY)) {
|
||||
if (!tasks.empty() && app_context.config->contains(CONFIG_NOTIFY)) {
|
||||
print_and_log(std::format("Sending notification for {} tasks", tasks.size()));
|
||||
|
||||
if (!app_context.config->contains(CONFIG_HOST)) {
|
||||
print_and_log_error("No NTFY host provided");
|
||||
return 1;
|
||||
@ -52,14 +54,27 @@ int current_tasks(const kc::AppContext &app_context)
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto host_name = (*app_context.config)[CONFIG_HOST].as<std::string>();
|
||||
auto topic_name = (*app_context.config)[CONFIG_TOPIC].as<std::string>();
|
||||
const auto host_name = (*app_context.config)[CONFIG_HOST].as<std::string>();
|
||||
const auto topic_name = (*app_context.config)[CONFIG_TOPIC].as<std::string>();
|
||||
|
||||
auto payload = get_notification_content(tasks);
|
||||
const auto payload = get_notification_content(tasks);
|
||||
|
||||
auto notif = kc::Notification(topic_name, payload);
|
||||
|
||||
kc::notify(host_name, notif);
|
||||
if (app_context.config->contains(CONFIG_TAGS)) {
|
||||
for (auto const& tag : (*app_context.config)[CONFIG_TAGS].as<std::vector<std::string>>()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Tagging notification with " << tag;
|
||||
notif.add_tag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
// kc::notify(host_name, notif);
|
||||
print_and_log("Notification sent");
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
print_and_log_error(std::format("Exception occurred while sending notification - {}", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace kc {
|
||||
|
||||
constexpr TaskState get_task_state(char c){
|
||||
constexpr TaskState get_task_state(const char c){
|
||||
switch(c){
|
||||
case ' ':
|
||||
return TaskState::NOT_STARTED;
|
||||
@ -17,7 +17,7 @@ constexpr TaskState get_task_state(char c){
|
||||
return TaskState::UNKNOWN;
|
||||
}
|
||||
|
||||
constexpr char get_task_state(TaskState c){
|
||||
constexpr char get_task_state(const TaskState c){
|
||||
switch(c){
|
||||
case TaskState::NOT_STARTED:
|
||||
return ' ';
|
||||
@ -32,29 +32,29 @@ constexpr char get_task_state(TaskState c){
|
||||
return '?';
|
||||
}
|
||||
|
||||
bool is_current(Task task) {
|
||||
bool is_current(const Task &task) {
|
||||
return is_current(task, day_clock::local_day());
|
||||
}
|
||||
|
||||
|
||||
bool is_current(Task task, date current_date) {
|
||||
bool is_current(const Task &task, const date current_date) {
|
||||
return task.get_due_date() <= current_date
|
||||
&& (task.get_state() == TaskState::NOT_STARTED || task.get_state() == TaskState::IN_PROGRESS);
|
||||
}
|
||||
|
||||
Task::Task(const std::string &task_content, TaskState state, const std::string &due_date_str)
|
||||
Task::Task(const std::string &task_content, const TaskState state, const std::string &due_date_str)
|
||||
: task_content(task_content), state(state), due_date(from_simple_string(due_date_str)) {
|
||||
}
|
||||
|
||||
Task::Task(const std::string &task_content, std::string state, const std::string &due_date_str)
|
||||
Task::Task(const std::string &task_content, const std::string &state, const std::string &due_date_str)
|
||||
: task_content(task_content), state(get_task_state(state[0])), due_date(from_simple_string(due_date_str)) {
|
||||
}
|
||||
|
||||
Task::Task(const std::string &task_content, TaskState state, const date &due_date_str)
|
||||
Task::Task(const std::string &task_content, const TaskState state, const date &due_date_str)
|
||||
: task_content(task_content), state(state), due_date(due_date_str) {
|
||||
}
|
||||
|
||||
Task::Task(const std::string &task_content, TaskState state)
|
||||
Task::Task(const std::string &task_content, const TaskState state)
|
||||
: task_content(task_content), state(state) {
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class Task {
|
||||
public:
|
||||
|
||||
explicit Task(const std::string &task_content, TaskState state, const std::string &due_date_str);
|
||||
explicit Task(const std::string &task_content, std::string state, const std::string &due_date_str);
|
||||
explicit Task(const std::string &task_content, const std::string &state, const std::string &due_date_str);
|
||||
explicit Task(const std::string &task_content, TaskState state, const date &due_date_str);
|
||||
explicit Task(const std::string &task_content, TaskState state);
|
||||
explicit Task(const std::string &task_content);
|
||||
@ -33,7 +33,7 @@ class Task {
|
||||
TaskState state;
|
||||
};
|
||||
|
||||
bool is_current(Task task);
|
||||
bool is_current(Task task, date current_date);
|
||||
bool is_current(const Task &task);
|
||||
bool is_current(const Task &task, date current_date);
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user