From fb27e8ed5030e6b5aa8df33cc4d347eacaef76ba Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Fri, 24 Feb 2017 23:15:28 +0100 Subject: make: parse runserver arguments from cli, instead of env this is some over-optimized parser, to celebrate #cloudbleed :D --- .gitignore | 1 + Makefile.am | 19 ++++++++ src/blogc-make/exec.c | 18 ++++--- src/blogc-make/exec.h | 3 +- src/blogc-make/main.c | 3 +- src/blogc-make/rules.c | 103 +++++++++++++++++++++++++++++----------- src/blogc-make/rules.h | 6 ++- tests/blogc-make/check_rules.c | 104 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 217 insertions(+), 40 deletions(-) create mode 100644 tests/blogc-make/check_rules.c diff --git a/.gitignore b/.gitignore index b6ded60..a530082 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ blogc*.html /tests/blogc-make/check_atom /tests/blogc-make/check_blogc_make.sh /tests/blogc-make/check_exec +/tests/blogc-make/check_rules /tests/blogc-make/check_settings /tests/blogc-runserver/check_httpd_utils /tests/blogc-runserver/check_mime diff --git a/Makefile.am b/Makefile.am index d1317d9..70b7b92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -758,6 +758,7 @@ if BUILD_MAKE_LIB check_PROGRAMS += \ tests/blogc-make/check_atom \ tests/blogc-make/check_exec \ + tests/blogc-make/check_rules \ tests/blogc-make/check_settings \ $(NULL) @@ -797,6 +798,24 @@ tests_blogc_make_check_exec_LDADD = \ libblogc_common.la \ $(NULL) +tests_blogc_make_check_rules_SOURCES = \ + tests/blogc-make/check_rules.c \ + $(NULL) + +tests_blogc_make_check_rules_CFLAGS = \ + $(CMOCKA_CFLAGS) \ + $(NULL) + +tests_blogc_make_check_rules_LDFLAGS = \ + -no-install \ + $(NULL) + +tests_blogc_make_check_rules_LDADD = \ + $(CMOCKA_LIBS) \ + libblogc_make.la \ + libblogc_common.la \ + $(NULL) + tests_blogc_make_check_settings_SOURCES = \ tests/blogc-make/check_settings.c \ $(NULL) diff --git a/src/blogc-make/exec.c b/src/blogc-make/exec.c index dafa6cb..bbba573 100644 --- a/src/blogc-make/exec.c +++ b/src/blogc-make/exec.c @@ -305,7 +305,8 @@ bm_exec_blogc(bm_settings_t *settings, bc_trie_t *variables, bool listing, int -bm_exec_blogc_runserver(const char *output_dir, bool verbose) +bm_exec_blogc_runserver(const char *output_dir, const char *host, + const char *port, const char *threads, bool verbose) { bc_string_t *cmd = bc_string_new(); @@ -320,23 +321,20 @@ bm_exec_blogc_runserver(const char *output_dir, bool verbose) bc_string_append(cmd, "blogc-runserver"); } - const char *runserver_host_tmp = getenv("RUNSERVER_HOST"); - if (runserver_host_tmp != NULL) { - char *tmp = bc_shell_quote(runserver_host_tmp); + if (host != NULL) { + char *tmp = bc_shell_quote(host); bc_string_append_printf(cmd, " -t %s", tmp); free(tmp); } - const char *runserver_port_tmp = getenv("RUNSERVER_PORT"); - if (runserver_port_tmp != NULL) { - char *tmp = bc_shell_quote(runserver_port_tmp); + if (port != NULL) { + char *tmp = bc_shell_quote(port); bc_string_append_printf(cmd, " -p %s", tmp); free(tmp); } - const char *runserver_threads_tmp = getenv("RUNSERVER_THREADS"); - if (runserver_threads_tmp != NULL) { - char *tmp = bc_shell_quote(runserver_threads_tmp); + if (threads != NULL) { + char *tmp = bc_shell_quote(threads); bc_string_append_printf(cmd, " -m %s", tmp); free(tmp); } diff --git a/src/blogc-make/exec.h b/src/blogc-make/exec.h index 8c42c9f..970befa 100644 --- a/src/blogc-make/exec.h +++ b/src/blogc-make/exec.h @@ -22,6 +22,7 @@ char* bm_exec_build_blogc_cmd(bm_settings_t *settings, bc_trie_t *variables, int bm_exec_blogc(bm_settings_t *settings, bc_trie_t *variables, bool listing, bm_filectx_t *template, bm_filectx_t *output, bc_slist_t *sources, bool verbose, bool only_first_source); -int bm_exec_blogc_runserver(const char *output_dir, bool verbose); +int bm_exec_blogc_runserver(const char *output_dir, const char *host, + const char *port, const char *threads, bool verbose); #endif /* _MAKE_EXEC_H */ diff --git a/src/blogc-make/main.c b/src/blogc-make/main.c index 98d4cc7..5f6a1e9 100644 --- a/src/blogc-make/main.c +++ b/src/blogc-make/main.c @@ -29,7 +29,8 @@ print_help(void) " - A simple build tool for blogc.\n" "\n" "positional arguments:\n" - " RULE build rule(s) to run (default: all)\n" + " RULE build rule(s) to run. can include comma-separated\n" + " key-value pairs of rule settings (default: all)\n" "\n" "optional arguments:\n" " -h show this help message and exit\n" diff --git a/src/blogc-make/rules.c b/src/blogc-make/rules.c index 9f5d9bc..36570f1 100644 --- a/src/blogc-make/rules.c +++ b/src/blogc-make/rules.c @@ -48,7 +48,7 @@ index_outputlist(bm_ctx_t *ctx) } static int -index_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +index_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL) return 0; @@ -106,7 +106,7 @@ atom_outputlist(bm_ctx_t *ctx) } static int -atom_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +atom_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL) return 0; @@ -167,7 +167,7 @@ atom_tags_outputlist(bm_ctx_t *ctx) } static int -atom_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +atom_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) return 0; @@ -241,7 +241,7 @@ pagination_outputlist(bm_ctx_t *ctx) } static int -pagination_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +pagination_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL) return 0; @@ -304,7 +304,7 @@ posts_outputlist(bm_ctx_t *ctx) } static int -posts_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +posts_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL) return 0; @@ -366,7 +366,7 @@ tags_outputlist(bm_ctx_t *ctx) } static int -tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) return 0; @@ -435,7 +435,7 @@ pages_outputlist(bm_ctx_t *ctx) } static int -pages_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +pages_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->pages == NULL) return 0; @@ -491,7 +491,7 @@ copy_outputlist(bm_ctx_t *ctx) } static int -copy_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +copy_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { if (ctx == NULL || ctx->settings->copy == NULL) return 0; @@ -527,7 +527,7 @@ clean_outputlist(bm_ctx_t *ctx) } static int -clean_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +clean_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { int rv = 0; @@ -551,7 +551,8 @@ clean_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) } -static int all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose); +static int all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, + bool verbose); // RUNSERVER RULE @@ -583,7 +584,7 @@ runserver_thread(void *arg) "reloader disabled!\n"); goto runserver_cleanup; } - if (0 != all_exec(args->ctx, NULL, args->verbose)) { + if (0 != all_exec(args->ctx, NULL, NULL, args->verbose)) { fprintf(stderr, "blogc-make: error: failed to rebuild website. " "reloader disabled!\n"); goto runserver_cleanup; @@ -599,20 +600,20 @@ runserver_cleanup: } static int -runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { // first 'all' call is syncronous, to do a 'sanity check' - int rv = all_exec(ctx, NULL, verbose); + int rv = all_exec(ctx, NULL, NULL, verbose); if (rv != 0) return rv; - runserver_args_t *args = bc_malloc(sizeof(runserver_args_t)); - args->ctx = ctx; - args->verbose = verbose; + runserver_args_t *r_args = bc_malloc(sizeof(runserver_args_t)); + r_args->ctx = ctx; + r_args->verbose = verbose; pthread_t thread; - if (0 != pthread_create(&thread, NULL, runserver_thread, args)) { + if (0 != pthread_create(&thread, NULL, runserver_thread, r_args)) { fprintf(stderr, "blogc-make: error: failed to create blogc-runserver " "thread!\n"); return 3; @@ -624,7 +625,8 @@ runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) return 3; } - bm_exec_blogc_runserver(ctx->output_dir, verbose); + bm_exec_blogc_runserver(ctx->output_dir, bc_trie_lookup(args, "host"), + bc_trie_lookup(args, "port"), bc_trie_lookup(args, "threads"), verbose); return 0; } @@ -714,14 +716,14 @@ const bm_rule_t rules[] = { // ALL RULE static int -all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) +all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args, bool verbose) { for (size_t i = 0; rules[i].name != NULL; i++) { if (!rules[i].generate_files) { continue; } - int rv = bm_rule_execute(ctx, &(rules[i]), verbose); + int rv = bm_rule_execute(ctx, &(rules[i]), NULL, verbose); if (rv != 0) { return rv; } @@ -730,6 +732,36 @@ all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose) } +bc_trie_t* +bm_rule_parse_args(const char *sep) +{ + if (sep == NULL || *sep == '\0' || *sep != ':') + return NULL; + + bc_trie_t *rv = bc_trie_new(free); + char *end = (char*) sep + 1; + char *kv_sep; + while (NULL != (kv_sep = strchr(end, '='))) { + char *key = bc_strndup(end, kv_sep - end); + end = kv_sep + 1; + kv_sep = strchr(end, ','); + if (kv_sep == NULL) + kv_sep = strchr(end, '\0'); + char *value = bc_strndup(end, kv_sep - end); + bc_trie_insert(rv, key, value); + free(key); + if (*kv_sep == '\0') + break; + end = kv_sep + 1; + } + if (kv_sep == NULL) { + bc_trie_free(rv); + return NULL; + } + return rv; +} + + int bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list, bool verbose) { @@ -740,18 +772,36 @@ bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list, bool verbose) int rv = 0; for (bc_slist_t *l = rule_list; l != NULL; l = l->next) { + + char *rule_str = l->data; + char *sep = strchr(rule_str, ':'); + + bc_trie_t *args = NULL; + if (sep == NULL) { + sep = strchr(rule_str, '\0'); + } + else { + args = bm_rule_parse_args(sep); + if (args == NULL) { + fprintf(stderr, "blogc-make: warning: failed to parse rule " + "arguments, ignoring: %s\n", rule_str); + } + } + rule = NULL; for (size_t i = 0; rules[i].name != NULL; i++) { - if (0 == strcmp((char*) l->data, rules[i].name)) { + if (strlen(rules[i].name) < (sep - rule_str)) + continue; + if (0 == strncmp(rule_str, rules[i].name, sep - rule_str)) { rule = &(rules[i]); - rv = bm_rule_execute(ctx, rule, verbose); + rv = bm_rule_execute(ctx, rule, args, verbose); if (rv != 0) return rv; } } if (rule == NULL) { - fprintf(stderr, "blogc-make: error: rule not found: %s\n", - (char*) l->data); + fprintf(stderr, "blogc-make: error: rule not found: %.*s\n", + (int) (sep - rule_str), rule_str); rv = 3; } } @@ -761,7 +811,8 @@ bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list, bool verbose) int -bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bool verbose) +bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bc_trie_t *args, + bool verbose) { if (ctx == NULL || rule == NULL) return 3; @@ -771,7 +822,7 @@ bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bool verbose) outputs = rule->outputlist_func(ctx); } - int rv = rule->exec_func(ctx, outputs, verbose); + int rv = rule->exec_func(ctx, outputs, args, verbose); bc_slist_free_full(outputs, (bc_free_func_t) bm_filectx_free); diff --git a/src/blogc-make/rules.h b/src/blogc-make/rules.h index b39e7be..7a15d45 100644 --- a/src/blogc-make/rules.h +++ b/src/blogc-make/rules.h @@ -15,7 +15,7 @@ typedef bc_slist_t* (*bm_rule_outputlist_func_t) (bm_ctx_t *ctx); typedef int (*bm_rule_exec_func_t) (bm_ctx_t *ctx, bc_slist_t *outputs, - bool verbose); + bc_trie_t *args, bool verbose); typedef struct { const char *name; @@ -25,8 +25,10 @@ typedef struct { bool generate_files; } bm_rule_t; +bc_trie_t* bm_rule_parse_args(const char *sep); int bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list, bool verbose); -int bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bool verbose); +int bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bc_trie_t *args, + bool verbose); bool bm_rule_need_rebuild(bc_slist_t *sources, bm_filectx_t *settings, bm_filectx_t *template, bm_filectx_t *output, bool only_first_source); bc_slist_t* bm_rule_list_built_files(bm_ctx_t *ctx); diff --git a/tests/blogc-make/check_rules.c b/tests/blogc-make/check_rules.c new file mode 100644 index 0000000..0ef8be7 --- /dev/null +++ b/tests/blogc-make/check_rules.c @@ -0,0 +1,104 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015-2017 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#include +#include +#include +#include + +#include +#include + +#include "../../src/blogc-make/rules.h" +#include "../../src/common/utils.h" + + +static void +test_rule_parse_args(void **state) +{ + bc_trie_t *t = bm_rule_parse_args("bola:foo=" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 1); + assert_string_equal(bc_trie_lookup(t, "foo"), ""); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 1); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=,baz=lol" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 2); + assert_string_equal(bc_trie_lookup(t, "foo"), ""); + assert_string_equal(bc_trie_lookup(t, "baz"), "lol"); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar,baz=" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 2); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + assert_string_equal(bc_trie_lookup(t, "baz"), ""); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar,baz=lol" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 2); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + assert_string_equal(bc_trie_lookup(t, "baz"), "lol"); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=,baz=lol,asd=qwe" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 3); + assert_string_equal(bc_trie_lookup(t, "foo"), ""); + assert_string_equal(bc_trie_lookup(t, "baz"), "lol"); + assert_string_equal(bc_trie_lookup(t, "asd"), "qwe"); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar,baz=,asd=qwe" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 3); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + assert_string_equal(bc_trie_lookup(t, "baz"), ""); + assert_string_equal(bc_trie_lookup(t, "asd"), "qwe"); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar,baz=lol,asd=" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 3); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + assert_string_equal(bc_trie_lookup(t, "baz"), "lol"); + assert_string_equal(bc_trie_lookup(t, "asd"), ""); + bc_trie_free(t); + t = bm_rule_parse_args("bola:foo=bar,baz=lol,asd=qwe" + 4); + assert_non_null(t); + assert_int_equal(bc_trie_size(t), 3); + assert_string_equal(bc_trie_lookup(t, "foo"), "bar"); + assert_string_equal(bc_trie_lookup(t, "baz"), "lol"); + assert_string_equal(bc_trie_lookup(t, "asd"), "qwe"); + bc_trie_free(t); +} + + +static void +test_rule_parse_args_error(void **state) +{ + assert_null(bm_rule_parse_args(NULL)); + assert_null(bm_rule_parse_args("bola" + 4)); + assert_null(bm_rule_parse_args("bola:" + 4)); + assert_null(bm_rule_parse_args("bola:asd" + 4)); + assert_null(bm_rule_parse_args("bola:asd=foo,lol" + 4)); + assert_null(bm_rule_parse_args("bola:asd=foo,qwe=bar,lol" + 4)); + assert_null(bm_rule_parse_args("bolaasd" + 4)); +} + + +int +main(void) +{ + const UnitTest tests[] = { + unit_test(test_rule_parse_args), + unit_test(test_rule_parse_args_error), + }; + return run_tests(tests); +} -- cgit v1.2.3-18-g5258