aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2018-05-13 02:39:28 +0200
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2018-05-13 19:38:32 +0200
commitf62faeb3ff69db2b1d27d775a7c30dbe4a78917c (patch)
tree217a48ef4e069369526f4438989849a0f17c3b2e
parent3be45bbbdc3f231926a30b2585a69b2e82918460 (diff)
downloadblogc-f62faeb3ff69db2b1d27d775a7c30dbe4a78917c.tar.gz
blogc-f62faeb3ff69db2b1d27d775a7c30dbe4a78917c.tar.bz2
blogc-f62faeb3ff69db2b1d27d775a7c30dbe4a78917c.zip
make: added 'watch' rule. improved 'runserver' rule.
-rw-r--r--Makefile.am2
-rw-r--r--src/blogc-make/httpd.c81
-rw-r--r--src/blogc-make/httpd.h19
-rw-r--r--src/blogc-make/reloader.c117
-rw-r--r--src/blogc-make/reloader.h13
-rw-r--r--src/blogc-make/rules.c27
6 files changed, 188 insertions, 71 deletions
diff --git a/Makefile.am b/Makefile.am
index 29c65d8..986685e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,7 @@ noinst_HEADERS = \
src/blogc-make/ctx.h \
src/blogc-make/exec.h \
src/blogc-make/exec-native.h \
+ src/blogc-make/httpd.h \
src/blogc-make/reloader.h \
src/blogc-make/rules.h \
src/blogc-make/settings.h \
@@ -233,6 +234,7 @@ libblogc_make_la_SOURCES = \
src/blogc-make/ctx.c \
src/blogc-make/exec.c \
src/blogc-make/exec-native.c \
+ src/blogc-make/httpd.c \
src/blogc-make/reloader.c \
src/blogc-make/rules.c \
src/blogc-make/settings.c \
diff --git a/src/blogc-make/httpd.c b/src/blogc-make/httpd.c
new file mode 100644
index 0000000..7d67b57
--- /dev/null
+++ b/src/blogc-make/httpd.c
@@ -0,0 +1,81 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2017 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "../common/utils.h"
+#include "ctx.h"
+#include "exec.h"
+#include "reloader.h"
+#include "httpd.h"
+
+// we are not going to unit-test these functions, then printing errors
+// directly is not a big issue
+
+
+typedef struct {
+ bm_ctx_t *ctx;
+ bc_trie_t *args;
+} bm_httpd_t;
+
+
+static void*
+httpd_thread(void *arg)
+{
+ bm_httpd_t *httpd = arg;
+
+ int rv = bm_exec_blogc_runserver(httpd->ctx, bc_trie_lookup(httpd->args, "host"),
+ bc_trie_lookup(httpd->args, "port"), bc_trie_lookup(httpd->args, "threads"));
+
+ free(httpd);
+
+ // stop the reloader
+ bm_reloader_stop(rv);
+
+ return NULL;
+}
+
+
+int
+bm_httpd_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, bc_slist_t *outputs,
+ bc_trie_t *args)
+{
+ int err;
+
+ pthread_attr_t attr;
+ if (0 != (err = pthread_attr_init(&attr))) {
+ fprintf(stderr, "blogc-make: error: failed to initialize httpd "
+ "thread attributes: %s\n", strerror(err));
+ return 3;
+ }
+
+ // we run the thread detached, because we don't want to wait it to join
+ // before exiting. the OS can clean it properly
+ if (0 != (err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) {
+ fprintf(stderr, "blogc-make: error: failed to mark httpd thread as "
+ "detached: %s\n", strerror(err));
+ return 3;
+ }
+
+ bm_httpd_t *rv = bc_malloc(sizeof(bm_httpd_t));
+ rv->ctx = *ctx;
+ rv->args = args;
+
+ pthread_t thread;
+ if (0 != (err = pthread_create(&thread, &attr, httpd_thread, rv))) {
+ fprintf(stderr, "blogc-make: error: failed to create httpd "
+ "thread: %s\n", strerror(err));
+ free(rv);
+ return 3;
+ }
+
+ // run the reloader
+ return bm_reloader_run(ctx, rule_exec, outputs, args);
+}
diff --git a/src/blogc-make/httpd.h b/src/blogc-make/httpd.h
new file mode 100644
index 0000000..97e3b86
--- /dev/null
+++ b/src/blogc-make/httpd.h
@@ -0,0 +1,19 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2017 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#ifndef _MAKE_HTTPD_H
+#define _MAKE_HTTPD_H
+
+#include "../common/utils.h"
+#include "ctx.h"
+#include "rules.h"
+
+int bm_httpd_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, bc_slist_t *outputs,
+ bc_trie_t *args);
+
+#endif /* _MAKE_HTTPD_H */
diff --git a/src/blogc-make/reloader.c b/src/blogc-make/reloader.c
index 6b30974..1bc7726 100644
--- a/src/blogc-make/reloader.c
+++ b/src/blogc-make/reloader.c
@@ -6,11 +6,14 @@
* See the file LICENSE.
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
+#include <errno.h>
#include "../common/utils.h"
#include "ctx.h"
#include "rules.h"
@@ -19,19 +22,52 @@
// we are not going to unit-test these functions, then printing errors
// directly is not a big issue
+static pthread_mutex_t mutex_running = PTHREAD_MUTEX_INITIALIZER;
+static bool running = false;
+static int handler_signum = 0;
+static void (*handler_func)(int) = NULL;
-static void*
-bm_reloader_thread(void *arg)
+
+int
+bm_reloader_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec,
+ bc_slist_t *outputs, bc_trie_t *args)
{
- bm_reloader_t *reloader = arg;
- while (reloader->running) {
- if (!bm_ctx_reload(&(reloader->ctx))) {
+ // install ^C handler
+ struct sigaction current_action;
+ if (sigaction(SIGINT, NULL, &current_action) < 0) {
+ fprintf(stderr, "blogc-make: failed to run reloader: %s\n", strerror(errno));
+ return 3;
+ }
+ if (current_action.sa_handler != bm_reloader_stop) { // not installed yet
+ // backup current handler
+ pthread_mutex_lock(&mutex_running);
+ handler_func = current_action.sa_handler;
+ pthread_mutex_unlock(&mutex_running);
+
+ // set new handler
+ struct sigaction new_action;
+ new_action.sa_handler = bm_reloader_stop;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+ if (sigaction(SIGINT, &new_action, NULL) < 0) {
+ fprintf(stderr, "blogc-make: failed to run reloader: %s\n",
+ strerror(errno));
+ return 3;
+ }
+ }
+
+ pthread_mutex_lock(&mutex_running);
+ running = true;
+ pthread_mutex_unlock(&mutex_running);
+
+ while (running) {
+ if (!bm_ctx_reload(ctx)) {
fprintf(stderr, "blogc-make: warning: failed to reload context. "
"retrying in 5 seconds ...\n\n");
sleep(5);
continue;
}
- if (0 != reloader->rule_exec(reloader->ctx, reloader->outputs, reloader->args)) {
+ if (0 != rule_exec(*ctx, outputs, args)) {
fprintf(stderr, "blogc-make: warning: failed to rebuild website. "
"retrying in 5 seconds ...\n\n");
sleep(5);
@@ -40,59 +76,38 @@ bm_reloader_thread(void *arg)
sleep(1);
}
- free(reloader);
- return NULL;
+ if (handler_signum > 0 && handler_signum <= SIGRTMAX)
+ return 128 + handler_signum;
+
+ return handler_signum;
}
-bm_reloader_t*
-bm_reloader_new(bm_ctx_t *ctx, bm_rule_exec_func_t rule_exec,
- bc_slist_t *outputs, bc_trie_t *args)
+void
+bm_reloader_stop(int signum)
{
- // first rule_exec call is syncronous, to do a 'sanity check'
- if (0 != rule_exec(ctx, outputs, args))
- return NULL;
+ pthread_mutex_lock(&mutex_running);
- int err;
+ handler_signum = signum > 128 ? signum - 128 : signum;
+ running = false;
- pthread_attr_t attr;
- if (0 != (err = pthread_attr_init(&attr))) {
- fprintf(stderr, "blogc-make: error: failed to initialize reloader "
- "thread attributes: %s\n", strerror(err));
- return NULL;
- }
+ // reraise if SIGINT
+ if (handler_signum == SIGINT) {
- // we run the thread detached, because we don't want to wait it to join
- // before exiting. the OS can clean it properly
- if (0 != (err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) {
- fprintf(stderr, "blogc-make: error: failed to mark reloader thread as "
- "detached: %s\n", strerror(err));
- return NULL;
- }
+ // reinstall old ^C handler
+ struct sigaction new_action;
+ new_action.sa_handler = handler_func;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+ sigaction(SIGINT, &new_action, NULL);
- bm_reloader_t *rv = bc_malloc(sizeof(bm_reloader_t));
- rv->ctx = ctx;
- rv->rule_exec = rule_exec;
- rv->outputs = outputs;
- rv->args = args;
- rv->running = true;
-
- pthread_t thread;
- if (0 != (err = pthread_create(&thread, &attr, bm_reloader_thread, rv))) {
- fprintf(stderr, "blogc-make: error: failed to create reloader "
- "thread: %s\n", strerror(err));
- free(rv);
- return NULL;
- }
-
- return rv;
-}
+ // run it
+ raise(SIGINT);
+ // SIGINT will usually kill the process, but in the case that the
+ // `handler_func` prevents it, our custom handler will be reinstalled
+ // by `bm_reloader_run`.
+ }
-void
-bm_reloader_stop(bm_reloader_t *reloader)
-{
- if (reloader == NULL)
- return;
- reloader->running = false;
+ pthread_mutex_unlock(&mutex_running);
}
diff --git a/src/blogc-make/reloader.h b/src/blogc-make/reloader.h
index 40d2fe9..cafd67c 100644
--- a/src/blogc-make/reloader.h
+++ b/src/blogc-make/reloader.h
@@ -9,21 +9,12 @@
#ifndef _MAKE_RELOADER_H
#define _MAKE_RELOADER_H
-#include <stdbool.h>
#include "../common/utils.h"
#include "ctx.h"
#include "rules.h"
-typedef struct {
- bm_ctx_t *ctx;
- bm_rule_exec_func_t rule_exec;
- bc_slist_t *outputs;
- bc_trie_t *args;
- bool running;
-} bm_reloader_t;
-
-bm_reloader_t* bm_reloader_new(bm_ctx_t *ctx, bm_rule_exec_func_t rule_exec,
+int bm_reloader_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec,
bc_slist_t *outputs, bc_trie_t *args);
-void bm_reloader_stop(bm_reloader_t *reloader);
+void bm_reloader_stop(int signum);
#endif /* _MAKE_RELOADER_H */
diff --git a/src/blogc-make/rules.c b/src/blogc-make/rules.c
index 8464bd2..5a23de7 100644
--- a/src/blogc-make/rules.c
+++ b/src/blogc-make/rules.c
@@ -16,6 +16,7 @@
#include "ctx.h"
#include "exec.h"
#include "exec-native.h"
+#include "httpd.h"
#include "reloader.h"
#include "settings.h"
#include "rules.h"
@@ -581,16 +582,16 @@ static int all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args);
static int
runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args)
{
- bm_reloader_t *reloader = bm_reloader_new(ctx, all_exec, outputs, args);
- if (reloader == NULL) {
- return 3;
- }
+ return bm_httpd_run(&ctx, all_exec, outputs, args);
+}
- int rv = bm_exec_blogc_runserver(ctx, bc_trie_lookup(args, "host"),
- bc_trie_lookup(args, "port"), bc_trie_lookup(args, "threads"));
- bm_reloader_stop(reloader);
- return rv;
+// WATCH RULE
+
+static int
+watch_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args)
+{
+ return bm_reloader_run(&ctx, all_exec, outputs, args);
}
@@ -667,12 +668,20 @@ const bm_rule_t rules[] = {
},
{
.name = "runserver",
- .help = "run blogc-runserver pointing to output directory, if available\n"
+ .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)",
.outputlist_func = NULL,
.exec_func = runserver_exec,
.generate_files = false,
},
+ {
+ .name = "watch",
+ .help = "watch for changes in the source files, rebuilding as needed",
+ .outputlist_func = NULL,
+ .exec_func = watch_exec,
+ .generate_files = false,
+ },
{NULL, NULL, NULL, NULL, false},
};