diff options
| -rw-r--r-- | src/blogc-make/ctx.c | 110 | ||||
| -rw-r--r-- | src/blogc-make/ctx.h | 6 | ||||
| -rw-r--r-- | src/blogc-make/main.c | 2 | ||||
| -rw-r--r-- | src/blogc-make/rules.c | 68 | 
4 files changed, 180 insertions, 6 deletions
diff --git a/src/blogc-make/ctx.c b/src/blogc-make/ctx.c index 39f1bf4..2dd4f97 100644 --- a/src/blogc-make/ctx.c +++ b/src/blogc-make/ctx.c @@ -50,6 +50,49 @@ bm_filectx_new(bm_ctx_t *ctx, const char *filename)  } +bool +bm_filectx_changed(bm_filectx_t *ctx, struct timespec *ts) +{ +    if (ctx == NULL) +        return false; + +    struct stat buf; + +    if (0 == stat(ctx->path, &buf)) { +        if (buf.st_mtim.tv_sec == ctx->timestamp.tv_sec) { +            if (buf.st_mtim.tv_nsec > ctx->timestamp.tv_nsec) { +                if (ts != NULL) +                    *ts = buf.st_mtim; +                return true; +            } +        } +        else if (buf.st_mtim.tv_sec > ctx->timestamp.tv_sec) { +            if (ts != NULL) +                *ts = buf.st_mtim; +            return true; +        } +    } + +    return false; +} + + +void +bm_filectx_reload(bm_filectx_t *ctx) +{ +    if (ctx == NULL) +        return; + +    struct timespec ts; + +    if (!bm_filectx_changed(ctx, &ts)) +        return; + +    ctx->timestamp = ts; +    ctx->readable = true; +} + +  void  bm_filectx_free(bm_filectx_t *fctx)  { @@ -62,7 +105,7 @@ bm_filectx_free(bm_filectx_t *fctx)  bm_ctx_t* -bm_ctx_new(const char *settings_file, bc_error_t **err) +bm_ctx_new(bm_ctx_t *base, const char *settings_file, bc_error_t **err)  {      if (settings_file == NULL || err == NULL || *err != NULL)          return NULL; @@ -92,7 +135,14 @@ bm_ctx_new(const char *settings_file, bc_error_t **err)          return NULL;      } -    bm_ctx_t *rv = bc_malloc(sizeof(bm_ctx_t)); +    bm_ctx_t *rv = NULL; +    if (base == NULL) { +        rv = bc_malloc(sizeof(bm_ctx_t)); +    } +    else { +        bm_ctx_free_internal(base); +        rv = base; +    }      rv->settings = settings;      char *real_filename = realpath(settings_file, NULL); @@ -108,6 +158,8 @@ bm_ctx_new(const char *settings_file, bc_error_t **err)          rv->output_dir = bc_strdup_printf("%s/%s", rv->root_dir, output_dir);      } +    // can't return null and set error after this! +      const char *template_dir = bc_trie_lookup(settings->settings,          "template_dir"); @@ -158,25 +210,77 @@ bm_ctx_new(const char *settings_file, bc_error_t **err)  void -bm_ctx_free(bm_ctx_t *ctx) +bm_ctx_reload(bm_ctx_t *ctx) +{ +    if (ctx == NULL || ctx->settings_fctx == NULL) +        return; + +    if (bm_filectx_changed(ctx->settings_fctx, NULL)) { +        // reload everything! we could just reload settings_fctx, as this +        // would force rebuilding everything, but we need to know new/deleted +        // files + +        // needs to dup path, because it may be freed when reloading. +        char *tmp = bc_strdup(ctx->settings_fctx->path); +        bc_error_t *err = NULL; +        ctx = bm_ctx_new(ctx, tmp, &err); +        free(tmp); +        if (err != NULL) {  // failed to reload, keep old ctx +            bc_error_print(err, "blogc-make"); +            bc_error_free(err); +        } +        return; +    } + +    bm_filectx_reload(ctx->main_template_fctx); +    bm_filectx_reload(ctx->atom_template_fctx); + +    for (bc_slist_t *tmp = ctx->posts_fctx; tmp != NULL; tmp = tmp->next) +        bm_filectx_reload((bm_filectx_t*) tmp->data); + +    for (bc_slist_t *tmp = ctx->pages_fctx; tmp != NULL; tmp = tmp->next) +        bm_filectx_reload((bm_filectx_t*) tmp->data); + +    for (bc_slist_t *tmp = ctx->copy_files_fctx; tmp != NULL; tmp = tmp->next) +        bm_filectx_reload((bm_filectx_t*) tmp->data); +} + + +void +bm_ctx_free_internal(bm_ctx_t *ctx)  {      if (ctx == NULL)          return;      bm_settings_free(ctx->settings); +    ctx->settings = NULL;      free(ctx->root_dir); +    ctx->root_dir = NULL;      free(ctx->output_dir); +    ctx->output_dir = NULL;      bm_atom_destroy(ctx->atom_template_fctx->path);      bm_filectx_free(ctx->main_template_fctx); +    ctx->main_template_fctx = NULL;      bm_filectx_free(ctx->atom_template_fctx); +    ctx->atom_template_fctx = NULL;      bm_filectx_free(ctx->settings_fctx); +    ctx->settings_fctx = NULL;      bc_slist_free_full(ctx->posts_fctx, (bc_free_func_t) bm_filectx_free); +    ctx->posts_fctx = NULL;      bc_slist_free_full(ctx->pages_fctx, (bc_free_func_t) bm_filectx_free); +    ctx->pages_fctx = NULL;      bc_slist_free_full(ctx->copy_files_fctx, (bc_free_func_t) bm_filectx_free); +    ctx->copy_files_fctx = NULL; +} + +void +bm_ctx_free(bm_ctx_t *ctx) +{ +    bm_ctx_free_internal(ctx);      free(ctx);  } diff --git a/src/blogc-make/ctx.h b/src/blogc-make/ctx.h index 05e85fc..7b68965 100644 --- a/src/blogc-make/ctx.h +++ b/src/blogc-make/ctx.h @@ -38,8 +38,12 @@ typedef struct {  } bm_ctx_t;  bm_filectx_t* bm_filectx_new(bm_ctx_t *ctx, const char *filename); +bool bm_filectx_changed(bm_filectx_t *ctx, struct timespec *ts); +void bm_filectx_reload(bm_filectx_t *ctx);  void bm_filectx_free(bm_filectx_t *fctx); -bm_ctx_t* bm_ctx_new(const char *filename, bc_error_t **err); +bm_ctx_t* bm_ctx_new(bm_ctx_t *base, const char *settings_file, bc_error_t **err); +void bm_ctx_reload(bm_ctx_t *ctx); +void bm_ctx_free_internal(bm_ctx_t *ctx);  void bm_ctx_free(bm_ctx_t *ctx);  #endif /* _MAKE_CTX_H */ diff --git a/src/blogc-make/main.c b/src/blogc-make/main.c index 1e43580..98d4cc7 100644 --- a/src/blogc-make/main.c +++ b/src/blogc-make/main.c @@ -104,7 +104,7 @@ main(int argc, char **argv)          rules = bc_slist_append(rules, bc_strdup("all"));      } -    ctx = bm_ctx_new(blogcfile ? blogcfile : "blogcfile", &err); +    ctx = bm_ctx_new(NULL, blogcfile ? blogcfile : "blogcfile", &err);      if (err != NULL) {          bc_error_print(err, "blogc-make");          rv = 3; diff --git a/src/blogc-make/rules.c b/src/blogc-make/rules.c index 711809a..1f18d5e 100644 --- a/src/blogc-make/rules.c +++ b/src/blogc-make/rules.c @@ -12,6 +12,9 @@  #include <stdlib.h>  #include <time.h>  #include <math.h> +#include <unistd.h> +#include <pthread.h> +#include <signal.h>  #include "../common/utils.h"  #include "ctx.h"  #include "exec.h" @@ -552,14 +555,77 @@ static int all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose);  // RUNSERVER RULE + +typedef struct { +    bm_ctx_t *ctx; +    bool verbose; +} runserver_args_t; + +static runserver_args_t *args = NULL; + +static void +runserver_sig_handler(int sig) +{ +    free(args); +    args = NULL; +} + +static void* +runserver_thread(void *arg) +{ +    signal(SIGINT, runserver_sig_handler); +    signal(SIGTERM, runserver_sig_handler); +    args = arg; +    while (true) { +        bm_ctx_reload(args->ctx); +        if (args->ctx == NULL) { +            fprintf(stderr, "blogc-make: error: failed to reload context. " +                "reloader disabled!\n"); +            goto runserver_cleanup; +        } +        if (0 != all_exec(args->ctx, NULL, args->verbose)) { +            fprintf(stderr, "blogc-make: error: failed to rebuild website. " +                "reloader disabled!\n"); +            goto runserver_cleanup; +        } +        sleep(1); +    } + +runserver_cleanup: +    free(args); +    args = NULL; + +    return NULL; +} +  static int  runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bool verbose)  { +    // first 'all' call is syncronous, to do a 'sanity check'      int rv = all_exec(ctx, NULL, verbose);      if (rv != 0)          return rv; -    return bm_exec_blogc_runserver(ctx->settings, verbose); +    runserver_args_t *args = bc_malloc(sizeof(runserver_args_t)); +    args->ctx = ctx; +    args->verbose = verbose; + +    pthread_t thread; + +    if (0 != pthread_create(&thread, NULL, runserver_thread, args)) { +        fprintf(stderr, "blogc-make: error: failed to create blogc-runserver " +            "thread!\n"); +        return 3; +    } + +    if (0 != pthread_detach(thread)) { +        fprintf(stderr, "blogc-make: error: failed to detach blogc-runserver " +            "thread!\n"); +        return 3; +    } + +    bm_exec_blogc_runserver(ctx->settings, verbose); +    return 0;  }  | 
