From 43a5963fb76f9e898182040a6670546f9eb301c2 Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Mon, 15 Jul 2019 22:19:27 +0200 Subject: make: rules: added pagination_tags needs tests, but is supposed to work --- Makefile.am | 1 - man/blogc-make.1.ronn | 12 +++ src/blogc-make/exec.c | 65 +++++++++++++++- src/blogc-make/exec.h | 7 +- src/blogc-make/main.c | 16 ++-- src/blogc-make/rules.c | 204 +++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 260 insertions(+), 45 deletions(-) diff --git a/Makefile.am b/Makefile.am index 12f9036..040f291 100644 --- a/Makefile.am +++ b/Makefile.am @@ -256,7 +256,6 @@ libblogc_make_la_CFLAGS = \ $(NULL) libblogc_make_la_LIBADD = \ - $(LIBM) \ $(PTHREAD_LIBS) \ libblogc_common.la \ $(NULL) diff --git a/man/blogc-make.1.ronn b/man/blogc-make.1.ronn index 76f2f37..d44b685 100644 --- a/man/blogc-make.1.ronn +++ b/man/blogc-make.1.ronn @@ -114,6 +114,18 @@ The rule passes the following helper variables to blogc(1): * `MAKE_TYPE`: `post` +### pagination_tags + +Build pagination pages for each tag from posts. This rule is disabled if +`posts_per_page` value in blogcfile(5) is negative or `0`. + +The rule passes the following helper variables to blogc(1): + + * `MAKE_RULE`: + `pagination_tags` + * `MAKE_TYPE`: + `post` + ### posts Build individual pages for each post. diff --git a/src/blogc-make/exec.c b/src/blogc-make/exec.c index c36dc2d..c282a91 100644 --- a/src/blogc-make/exec.c +++ b/src/blogc-make/exec.c @@ -289,9 +289,8 @@ bm_exec_build_blogc_cmd(const char *blogc_bin, bm_settings_t *settings, int bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, bc_trie_t *local_variables, - const char *print, bool listing, bm_filectx_t *listing_entry, - bm_filectx_t *template, bm_filectx_t *output, bc_slist_t *sources, - bool only_first_source) + bool listing, bm_filectx_t *listing_entry, bm_filectx_t *template, + bm_filectx_t *output, bc_slist_t *sources, bool only_first_source) { if (ctx == NULL) return 1; @@ -304,7 +303,7 @@ bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, bc_trie_t *local_varia } char *cmd = bm_exec_build_blogc_cmd(ctx->blogc, ctx->settings, global_variables, - local_variables, print, listing, listing_entry == NULL ? NULL : listing_entry->path, + local_variables, NULL, listing, listing_entry == NULL ? NULL : listing_entry->path, template->path, output->path, ctx->dev, input->len > 0); if (ctx->verbose) @@ -370,6 +369,64 @@ bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, bc_trie_t *local_varia } +char* +bm_exec_blogc_get_variable(bm_ctx_t *ctx, bc_trie_t *global_variables, + bc_trie_t *local_variables, const char *variable, bool listing, + bc_slist_t *sources, bool only_first_source) +{ + if (ctx == NULL) + return NULL; + + bc_string_t *input = bc_string_new(); + for (bc_slist_t *l = sources; l != NULL; l = l->next) { + bc_string_append_printf(input, "%s\n", ((bm_filectx_t*) l->data)->path); + if (only_first_source) + break; + } + + char *cmd = bm_exec_build_blogc_cmd(ctx->blogc, ctx->settings, global_variables, + local_variables, variable, listing, NULL, NULL, NULL, ctx->dev, input->len > 0); + + if (ctx->verbose) + printf("%s\n", cmd); + fflush(stdout); + + char *out = NULL; + char *err = NULL; + bc_error_t *error = NULL; + + int rv = bm_exec_command(cmd, input->str, &out, &err, &error); + + if (error != NULL) { + bc_error_print(error, "blogc-make"); + bc_error_free(error); + bc_string_free(input, true); + free(cmd); + free(out); + free(err); + return NULL; + } + + if (rv != 0) { + fprintf(stderr, "blogc-make: error: %s\n", bc_str_strip(err)); + bc_string_free(input, true); + free(cmd); + free(out); + free(err); + return NULL; + } + + char *val = bc_strndup(out, strlen(out) - 1); + + bc_string_free(input, true); + free(cmd); + free(out); + free(err); + + return val; +} + + int bm_exec_blogc_runserver(bm_ctx_t *ctx, const char *host, const char *port, const char *threads) diff --git a/src/blogc-make/exec.h b/src/blogc-make/exec.h index 140ef62..6bc206f 100644 --- a/src/blogc-make/exec.h +++ b/src/blogc-make/exec.h @@ -22,10 +22,13 @@ char* bm_exec_build_blogc_cmd(const char *blogc_bin, bm_settings_t *settings, bc_trie_t *global_variables, bc_trie_t *local_variables, const char *print, bool listing, const char *listing_entry, const char *template, const char *output, bool dev, bool sources_stdin); -int bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, bc_trie_t *local_variables, - const char *print, bool listing, bm_filectx_t *listing_entry, +int bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, + bc_trie_t *local_variables, bool listing, bm_filectx_t *listing_entry, bm_filectx_t *template, bm_filectx_t *output, bc_slist_t *sources, bool only_first_source); +char* bm_exec_blogc_get_variable(bm_ctx_t *ctx, bc_trie_t *global_variables, + bc_trie_t *local_variables, const char *variable, bool listing, + bc_slist_t *sources, bool only_first_source); int bm_exec_blogc_runserver(bm_ctx_t *ctx, const char *host, const char *port, const char *threads); diff --git a/src/blogc-make/main.c b/src/blogc-make/main.c index d9f60b9..5b4a030 100644 --- a/src/blogc-make/main.c +++ b/src/blogc-make/main.c @@ -29,16 +29,16 @@ print_help(void) " - A simple build tool for blogc.\n" "\n" "positional arguments:\n" - " RULE build rule(s) to run. can include comma-separated\n" - " key-value pairs of rule arguments in the format\n" - " RULE:arg1=value1,arg2=value2,... (default: all)\n" + " RULE build rule(s) to run. can include comma-separated\n" + " key-value pairs of rule arguments in the format\n" + " RULE:arg1=value1,arg2=value2,... (default: all)\n" "\n" "optional arguments:\n" - " -h show this help message and exit\n" - " -v show version and exit\n" - " -D build for development environment\n" - " -V be verbose when executing commands\n" - " -f FILE read FILE as blogcfile\n"); + " -h show this help message and exit\n" + " -v show version and exit\n" + " -D build for development environment\n" + " -V be verbose when executing commands\n" + " -f FILE read FILE as blogcfile\n"); bm_rule_print_help(); } diff --git a/src/blogc-make/rules.c b/src/blogc-make/rules.c index 422f3a4..4d7a43e 100644 --- a/src/blogc-make/rules.c +++ b/src/blogc-make/rules.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "../common/utils.h" #include "atom.h" #include "ctx.h" @@ -117,9 +116,8 @@ index_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) { - rv = bm_exec_blogc(ctx, variables, NULL, NULL, true, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, - ctx->posts_fctx, false); + rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, + ctx->main_template_fctx, fctx, ctx->posts_fctx, false); if (rv != 0) break; } @@ -177,8 +175,8 @@ atom_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, NULL, NULL, fctx, false)) { - rv = bm_exec_blogc(ctx, variables, NULL, NULL, true, NULL, - ctx->atom_template_fctx, fctx, ctx->posts_fctx, false); + rv = bm_exec_blogc(ctx, variables, NULL, true, NULL, ctx->atom_template_fctx, + fctx, ctx->posts_fctx, false); if (rv != 0) break; } @@ -243,8 +241,8 @@ atom_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, NULL, NULL, fctx, false)) { - rv = bm_exec_blogc(ctx, variables, NULL, NULL, true, NULL, - ctx->atom_template_fctx, fctx, ctx->posts_fctx, false); + rv = bm_exec_blogc(ctx, variables, NULL, true, NULL, ctx->atom_template_fctx, + fctx, ctx->posts_fctx, false); if (rv != 0) break; } @@ -264,17 +262,24 @@ pagination_outputlist(bm_ctx_t *ctx) if (ctx == NULL || ctx->settings->posts == NULL) return NULL; - // not using posts_pagination_enabled() here because we need to calculate - // posts per page here anyway, and the condition is different. - long posts_per_page = strtol(bm_ctx_settings_lookup_str(ctx, "posts_per_page"), - NULL, 10); - if (posts_per_page <= 0) + if (!posts_pagination_enabled(ctx, "posts_per_page")) return NULL; - bc_slist_t *rv = NULL; + bc_trie_t *variables = bc_trie_new(free); + posts_pagination(ctx, variables, "posts_per_page"); + + char *last_page = bm_exec_blogc_get_variable(ctx, variables, NULL, "LAST_PAGE", + true, ctx->posts_fctx, false); + + bc_trie_free(variables); + + if (last_page == NULL) + return NULL; - long num_posts = bc_slist_length(ctx->posts_fctx); - size_t pages = ceilf(((float) num_posts) / posts_per_page); + long pages = strtol(last_page, NULL, 10); + free(last_page); + + bc_slist_t *rv = NULL; const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); @@ -319,9 +324,142 @@ pagination_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) { - rv = bm_exec_blogc(ctx, variables, NULL, NULL, true, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, - ctx->posts_fctx, false); + rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, + ctx->main_template_fctx, fctx, ctx->posts_fctx, false); + if (rv != 0) + break; + } + } + + bc_trie_free(variables); + + return rv; +} + + +// PAGINATION TAGS RULE + +static bc_slist_t* +pagination_tags_outputlist(bm_ctx_t *ctx) +{ + if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) + return NULL; + + if (!posts_pagination_enabled(ctx, "posts_per_page")) + return NULL; + + bc_trie_t *variables = bc_trie_new(free); + posts_pagination(ctx, variables, "posts_per_page"); + + const char *tag_prefix = bm_ctx_settings_lookup(ctx, "tag_prefix"); + const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); + const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); + + bc_slist_t *rv = NULL; + + for (size_t k = 0; ctx->settings->tags[k] != NULL; k++) { + bc_trie_t *local = bc_trie_new(free); + bc_trie_insert(local, "FILTER_TAG", bc_strdup(ctx->settings->tags[k])); + + char *last_page = bm_exec_blogc_get_variable(ctx, variables, local, + "LAST_PAGE", true, ctx->posts_fctx, false); + + bc_trie_free(local); + + if (last_page == NULL) + break; + + long pages = strtol(last_page, NULL, 10); + free(last_page); + + char *prefix = bc_strdup_printf("%s/%s/%s", tag_prefix, + ctx->settings->tags[k], pagination_prefix); + + for (size_t i = 0; i < pages; i++) { + char *j = bc_strdup_printf("%d", i + 1); + char *f = bm_generate_filename(ctx->short_output_dir, prefix, + j, html_ext); + rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); + free(j); + free(f); + } + + free(prefix); + } + + bc_trie_free(variables); + + return rv; +} + +static int +pagination_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) +{ + if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) + return 0; + + int rv = 0; + size_t page = 1; + + bc_trie_t *variables = bc_trie_new(free); + // not using posts_pagination because we set FILTER_PAGE anyway, and the + // first value inserted in that function would be useless + bc_trie_insert(variables, "FILTER_PER_PAGE", + bc_strdup(bm_ctx_settings_lookup_str(ctx, "posts_per_page"))); + posts_ordering(ctx, variables, "html_order"); + bc_trie_insert(variables, "DATE_FORMAT", + bc_strdup(bm_ctx_settings_lookup_str(ctx, "date_format"))); + bc_trie_insert(variables, "MAKE_RULE", bc_strdup("pagination_tags")); + bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); + + const char *tag_prefix = bm_ctx_settings_lookup(ctx, "tag_prefix"); + const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); + const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); + + for (bc_slist_t *l = outputs; l != NULL; l = l->next, page++) { + bm_filectx_t *fctx = l->data; + if (fctx == NULL) + continue; + + // this is very expensive, but we don't have another way to detect the + // tag and page from the file path right now :/ + char *tag = NULL; + for (size_t i = 0; ctx->settings->tags[i] != NULL; i++) { + char *prefix = bc_strdup_printf("%s/%s/%s", tag_prefix, + ctx->settings->tags[i], pagination_prefix); + bool b = false; + + // it is impossible to have more output files per tag than the whole + // amount of output pages + for (size_t k = 0; k < bc_slist_length(outputs); k++) { + char *j = bc_strdup_printf("%d", k + 1); + char *f = bm_generate_filename(ctx->short_output_dir, prefix, + j, html_ext); + free(j); + if (0 == strcmp(fctx->short_path, f)) { + tag = ctx->settings->tags[i]; + page = k + 1; + b = true; + free(f); + break; + } + free(f); + } + free(prefix); + if (b) + break; + } + if (tag == NULL) + continue; + + bc_trie_insert(variables, "FILTER_TAG", bc_strdup(tag)); + bc_trie_insert(variables, "FILTER_PAGE", bc_strdup_printf("%zu", page)); + + if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, + ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) + { + rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, + ctx->main_template_fctx, fctx, ctx->posts_fctx, false); if (rv != 0) break; } @@ -386,8 +524,8 @@ posts_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) { bc_trie_t *local = bc_trie_new(NULL); bc_trie_insert(local, "MAKE_SLUG", s_fctx->slug); // no need to copy - rv = bm_exec_blogc(ctx, variables, local, NULL, false, NULL, - ctx->main_template_fctx, o_fctx, s, true); + rv = bm_exec_blogc(ctx, variables, local, false, NULL, ctx->main_template_fctx, + o_fctx, s, true); bc_trie_free(local); if (rv != 0) break; @@ -454,9 +592,8 @@ tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) { - rv = bm_exec_blogc(ctx, variables, NULL, NULL, true, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, - ctx->posts_fctx, false); + rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, + ctx->main_template_fctx, fctx, ctx->posts_fctx, false); if (rv != 0) break; } @@ -518,8 +655,8 @@ pages_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) { bc_trie_t *local = bc_trie_new(NULL); bc_trie_insert(local, "MAKE_SLUG", s_fctx->slug); // no need to copy - rv = bm_exec_blogc(ctx, variables, local, NULL, false, NULL, - ctx->main_template_fctx, o_fctx, s, true); + rv = bm_exec_blogc(ctx, variables, local, false, NULL, ctx->main_template_fctx, + o_fctx, s, true); bc_trie_free(local); if (rv != 0) break; @@ -686,6 +823,13 @@ const bm_rule_t rules[] = { .exec_func = pagination_exec, .generate_files = true, }, + { + .name = "pagination_tags", + .help = "build pagination pages for each tag from posts", + .outputlist_func = pagination_tags_outputlist, + .exec_func = pagination_tags_exec, + .generate_files = true, + }, { .name = "posts", .help = "build individual pages for each post", @@ -724,8 +868,8 @@ const bm_rule_t rules[] = { { .name = "runserver", .help = "run blogc-runserver pointing to output directory, if available,\n" - " rebuilding as needed\n" - " arguments: host (127.0.0.1), port (8080) and threads (20)", + " rebuilding as needed\n" + " arguments: host (127.0.0.1), port (8080) and threads (20)", .outputlist_func = NULL, .exec_func = runserver_exec, .generate_files = false, @@ -946,13 +1090,13 @@ bm_rule_print_help(void) printf("\nhelper rules:\n"); for (size_t i = 0; rules[i].name != NULL; i++) { if (!rules[i].generate_files) { - printf(" %-12s %s\n", rules[i].name, rules[i].help); + printf(" %-15s %s\n", rules[i].name, rules[i].help); } } printf("\nbuild rules:\n"); for (size_t i = 0; rules[i].name != NULL; i++) { if (rules[i].generate_files) { - printf(" %-12s %s\n", rules[i].name, rules[i].help); + printf(" %-15s %s\n", rules[i].name, rules[i].help); } } } -- cgit v1.2.3-18-g5258