Browse Source

full content rss feed

master
alistair 3 years ago
parent
commit
164113105d
  1. 219
      main.cpp

219
main.cpp

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
#include <iostream>
#include <filesystem>
#include <sstream>
#include <stdexcept>
#include <string>
#include <cstdlib>
#include <optional>
@ -43,6 +44,23 @@ const std::string TEMPLATE_CODE_END = "}}"; @@ -43,6 +44,23 @@ const std::string TEMPLATE_CODE_END = "}}";
using json = nlohmann::json;
namespace fs = std::filesystem;
enum job_type {
COPY_FILE = 1,
MARKDOWN = 1 << 1,
TEMPLATE = 1 << 2,
DELETE_FILE = 1 << 3,
MAKE_DIR = 1 << 4
};
struct blog_item {
job_type type;
fs::path src;
std::map<std::string, std::string> properties;
time_t post_date;
};
template <typename TP>
std::time_t to_time_t(TP tp)
{
@ -325,6 +343,24 @@ class substitution_plugin { @@ -325,6 +343,24 @@ class substitution_plugin {
virtual ~substitution_plugin() = default;
};
class s2_substitution_plugin : public substitution_plugin {
public:
int
perform_substitution(int start, int end, const std::string &invocation,
std::string &file_text,
const std::map<std::string, std::string> &properties) override
{
return 0;
}
/* Must return lengh of replaced text */
virtual int
perform_substitution(int start, int end, const std::string &invocation,
std::string &file_text,
const std::map<std::string, std::string> &properties,
const std::map<fs::path, blog_item> & pages) = 0;
};
/*
* Returns vector of arguments from string of the form " cmdname:arg1 :arg2 ".
@ -369,7 +405,6 @@ std::vector<std::string> substitution_plugin::get_arguments(const std::string &i @@ -369,7 +405,6 @@ std::vector<std::string> substitution_plugin::get_arguments(const std::string &i
}
class file_transclude_plugin : public substitution_plugin {
public:
inline static const std::string hook_name = "include";
@ -426,8 +461,6 @@ class mmd_snippet_transclude_plugin : public substitution_plugin { @@ -426,8 +461,6 @@ class mmd_snippet_transclude_plugin : public substitution_plugin {
}
};
class variable_transclude_plugin final : public substitution_plugin {
public:
inline static const std::string hook_name = "";
@ -823,16 +856,27 @@ class feed_builder { @@ -823,16 +856,27 @@ class feed_builder {
tinyxml2::XMLElement *add_article(std::string const &url, std::string const &title, const std::string &category, time_t updated, time_t published) {
auto article = add_article(url, title, updated, published);
auto e_category = article->InsertNewChildElement("category");
e_category->SetAttribute("term", category.c_str());
return article;
}
tinyxml2::XMLElement *add_article(std::string const &url, std::string const &title, const std::string &category, time_t updated, time_t published, std::string content) {
auto article = add_article(url, title, updated, published);
auto e_category = article->InsertNewChildElement("category");
e_category->SetAttribute("term", category.c_str());
auto e_content = article->InsertNewChildElement("content");
e_content->SetText(content.c_str());
e_content->SetAttribute("type", "html");
return article;
}
};
class rss_feed_plugin : public substitution_plugin {
class rss_feed_plugin : public s2_substitution_plugin {
public:
@ -842,9 +886,8 @@ class rss_feed_plugin : public substitution_plugin { @@ -842,9 +886,8 @@ class rss_feed_plugin : public substitution_plugin {
int perform_substitution(int start, int end, const std::string &invocation,
std::string &file_text,
const std::map<std::string, std::string> &properties) override {
const std::map<std::string, std::string> &properties, const std::map<fs::path, blog_item> & pages) override {
auto args = get_arguments(invocation, 1);
std::string relpath = args.at(1);
@ -874,6 +917,26 @@ class rss_feed_plugin : public substitution_plugin { @@ -874,6 +917,26 @@ class rss_feed_plugin : public substitution_plugin {
next = relpath.find(",", first);
}
std::multimap<time_t, blog_item> feed_items;
for (std::string dir: paths) {
for (auto &page: pages) {
if (!(page.second.type & (job_type::TEMPLATE | job_type::MARKDOWN))) {
continue;
}
if (page.first.filename() == "index.html") {
continue;
}
if (page.second.src.string().find(dir) != std::string::npos) {
// this is a page to add
feed_items.insert({page.second.post_date, page.second});
}
}
}
/*
file_index_plugin p {};
std::multimap<time_t, file_index_plugin::post_entry> entries;
@ -897,22 +960,36 @@ class rss_feed_plugin : public substitution_plugin { @@ -897,22 +960,36 @@ class rss_feed_plugin : public substitution_plugin {
}
}
}
*/
feed_builder f {compute_url(properties.at("current_file"), properties), properties.at("name"), {properties.at("author")}};
for (auto entry = entries.rbegin(); entry != entries.rend(); entry++) {
for (auto entry = feed_items.rbegin(); entry != feed_items.rend(); entry++) {
// write into rss feed
if (!fs::is_directory(entry->second.path)) {
std::string category = entry->second.path.parent_path().filename().string();
f.add_article(compute_url(entry->second.path, properties), entry->second.title, category, entry->first, entry->first);
std::string category = entry->second.src.parent_path().filename().string();
std::string title;
if (entry->second.properties.count("title"))
title = entry->second.properties.at("title");
else
title = entry->second.src.filename().string();
std::string content;
if (entry->second.properties.count("original")) {
content = entry->second.properties.at("original");
} else {
// fall back to full generated page.
content = entry->second.properties.at("body");
}
f.add_article(compute_url(entry->second.src, properties), title, category, entry->second.post_date, entry->second.post_date, content);
}
std::string text = f.str();
file_text.replace(start, end - start, text);
std::cout << text;
return text.length();
}
};
@ -923,24 +1000,12 @@ class builder { @@ -923,24 +1000,12 @@ class builder {
mmd::markdown_parser parser;
std::map<std::string, substitution_plugin *> substitution_commands;
std::map<std::string, s2_substitution_plugin *> s2_substitution_commands;
std::map<std::string, std::string> default_templates;
std::map<std::string, std::string> properties;
const std::set<std::string> apply_templates_exts {"md","html", "txt", "markdown", "xml"};
enum job_type {
COPY_FILE = 1,
MARKDOWN = 1 << 1,
TEMPLATE = 1 << 2,
DELETE_FILE = 1 << 3,
MAKE_DIR = 1 << 4
};
const std::set<std::string> apply_templates_exts {"md","html", "txt", "markdown", "xml", "atom", "rss"};
struct blog_item {
job_type type;
fs::path src;
std::map<std::string, std::string> properties;
};
void
@ -952,14 +1017,15 @@ class builder { @@ -952,14 +1017,15 @@ class builder {
substitution_commands[ifndef_plugin::hook_name] = new ifndef_plugin{};
substitution_commands[file_transclude_plugin::hook_name] = new file_transclude_plugin{};
substitution_commands[mmd_snippet_transclude_plugin::hook_name] = new mmd_snippet_transclude_plugin{};
substitution_commands[rss_feed_plugin::hook_name] = new rss_feed_plugin{};
s2_substitution_commands[rss_feed_plugin::hook_name] = new rss_feed_plugin{};
}
int
do_substitution(int start, int end, const std::string &invocation,
std::string &file_text,
const std::map<std::string, std::string> &properties)
const std::map<std::string, std::string> &properties,
std::optional<const std::map<fs::path, blog_item>> pages)
{
assert(substitution_commands.size() > 0);
@ -970,12 +1036,26 @@ class builder { @@ -970,12 +1036,26 @@ class builder {
start, end, invocation, file_text, properties);
}
if (pages) {
if (s2_substitution_commands.count(command_name)) {
return s2_substitution_commands.at(command_name)->perform_substitution(
start, end, invocation, file_text, properties, *pages);
}
}
return 0;
}
void
run_substitution_plugins(std::string &text,
const std::map<std::string, std::string> &properties)
void
run_substitution_plugins(std::string &text,
const std::map<std::string, std::string> &properties)
{
run_substitution_plugins(text, properties, {});
}
void
run_substitution_plugins(std::string &text,
const std::map<std::string, std::string> &properties, std::optional<const std::map<fs::path, blog_item>> pages)
{
std::string::size_type next = text.find(TEMPLATE_CODE_START, 0);
@ -1036,8 +1116,7 @@ class builder { @@ -1036,8 +1116,7 @@ class builder {
end += TEMPLATE_CODE_END.length();
int subst = do_substitution(next, end, invocation, text, properties);
int subst = do_substitution(next, end, invocation, text, properties, pages);
if (!subst) {
// unsuccesful
next += TEMPLATE_CODE_START.length();
@ -1111,9 +1190,8 @@ class builder { @@ -1111,9 +1190,8 @@ class builder {
}
}
/* DO NOTHING BEFORE HERE */
time_t dir_last_update_time = to_time_t(fs::last_write_time(directory));
compile_jobs[compute_target(directory, properties)] = {job_type::MAKE_DIR, directory};
// first pass of directory
//
@ -1177,6 +1255,8 @@ class builder { @@ -1177,6 +1255,8 @@ class builder {
for (fs::path entry: next_files) {
time_t article_last_update = to_time_t(fs::last_write_time(entry));
if (file_ext(entry) == "draft") {
continue;
}
@ -1204,8 +1284,27 @@ class builder { @@ -1204,8 +1284,27 @@ class builder {
article_properties["target"] = target.string();
if (article_properties.count("date")) {
std::istringstream in {article_properties.at("date")};
date::sys_seconds timepoint;
in >> date::parse(article_properties.at("date-in-format"), timepoint);
time_t t = std::chrono::system_clock::to_time_t(timepoint);
if (t != (time_t){}) {
article_last_update = t;
if (t > dir_last_update_time) {
dir_last_update_time = t;
}
} else {
spdlog::info("ba d date parse");
}
std::string ndate = reformat_date(article_properties.at("date"), article_properties);
article_properties["date"] = ndate;
}
if (!article_properties.count("notemplating")) {
@ -1231,6 +1330,8 @@ class builder { @@ -1231,6 +1330,8 @@ class builder {
article_properties["body"] = html;
}
article_properties["original"] = article_properties["body"];
std::string new_page {};
/*
if (page_templates.count(default_template_name)) {
@ -1259,7 +1360,7 @@ class builder { @@ -1259,7 +1360,7 @@ class builder {
article_properties["body"] = new_page;
notify_file_write(target);
compile_jobs[target] = {job_type::TEMPLATE, entry, std::map<std::string, std::string>(article_properties)};
compile_jobs[target] = {job_type::TEMPLATE, entry, std::map<std::string, std::string>(article_properties), article_last_update};
continue;
}
@ -1267,7 +1368,7 @@ class builder { @@ -1267,7 +1368,7 @@ class builder {
// else just copy
auto target = compute_target(entry, article_properties);
notify_file_write(target);
compile_jobs[target] = {job_type::COPY_FILE, entry, std::map<std::string, std::string>(article_properties)};
compile_jobs[target] = {job_type::COPY_FILE, entry, std::map<std::string, std::string>(article_properties), dir_last_update_time};
// build
@ -1290,12 +1391,21 @@ class builder { @@ -1290,12 +1391,21 @@ class builder {
}
compile_jobs[compute_target(directory, properties)] = {job_type::MAKE_DIR, directory, std::map<std::string, std::string>(properties), dir_last_update_time};
// recurse
for (auto d : next_directories) {
build_recursive(std::map<std::string, std::string>(page_templates),
std::map<std::string, std::string>(properties), compile_jobs, d);
}
if (directory.string() != properties.at("source_root")) {
time_t *parent_date = &compile_jobs.at(compute_target(directory.parent_path(), properties)).post_date;
if (*parent_date < dir_last_update_time) {
*parent_date = dir_last_update_time;
}
}
}
void
@ -1361,6 +1471,9 @@ class builder { @@ -1361,6 +1471,9 @@ class builder {
for (auto e : substitution_commands) {
delete e.second;
}
for (auto e: s2_substitution_commands) {
delete e.second;
}
}
@ -1386,43 +1499,47 @@ class builder { @@ -1386,43 +1499,47 @@ class builder {
write_build(std::map<fs::path, blog_item> &compile_jobs)
{
for (auto e: compile_jobs) {
// make directory structure
for (auto &e: compile_jobs) {
if (job_type::MAKE_DIR & e.second.type) {
fs::create_directories(e.first);
}
}
// do copy and deletions
for (auto &e : compile_jobs) {
auto src = e.second.src;
auto dest = e.first;
if (job_type::COPY_FILE & e.second.type) {
fs::copy(src, dest, fs::copy_options::update_existing);
}
if (job_type::MAKE_DIR & e.second.type) {
fs::create_directories(e.first);
}
if (job_type::DELETE_FILE & e.second.type) {
fs::remove_all(e.first);
}
}
for (auto e: compile_jobs) {
for (auto &e: compile_jobs) {
if (job_type::TEMPLATE & e.second.type) {
// reapply stg1 and stg2 templates
std::string page = e.second.properties.at("body");
run_substitution_plugins(page,
e.second.properties, compile_jobs);
e.second.properties["body"] = page;
}
if (job_type::MARKDOWN & e.second.type) {
// run markdown
}
}
for (auto e: compile_jobs) {
for (auto &e: compile_jobs) {
}
for (auto e: compile_jobs) {
for (auto &e: compile_jobs) {
if ((job_type::MARKDOWN | job_type::TEMPLATE) & e.second.type) {
write_file(e.first, e.second.properties.at("body"));
write_file(e.first.string(), e.second.properties.at("body"));
}
}
}

Loading…
Cancel
Save