diff options
| author | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-03-25 13:22:42 -0400 |
|---|---|---|
| committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-03-25 13:22:42 -0400 |
| commit | 44342619d43375313b56f7c530c4532b0f69be25 (patch) | |
| tree | cbb68df916001a3b6c3ea17eeea40e28cdc8f307 /target.c | |
| parent | d79588bdf85b8c1514019e679c7eefbc9014edd9 (diff) | |
| download | do-44342619d43375313b56f7c530c4532b0f69be25.tar.gz | |
Refactor program structure
Diffstat (limited to 'target.c')
| -rw-r--r-- | target.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/target.c b/target.c new file mode 100644 index 0000000..bbda4e6 --- /dev/null +++ b/target.c @@ -0,0 +1,131 @@ +#include "common.h" + +struct Target *target_new() { + struct Target *t = calloc(1, sizeof(struct Target)); + return t; +} + +struct Target *target_clone(const struct Target *src) { + struct Target *t = target_new(); + if (!t) { + fprintf(stderr, "unable to allocate memory to clone target\n"); + return NULL; + } + t->id = src->id ? strdup(src->id) : NULL; + t->_tmp_deps = src->_tmp_deps ? strdup(src->_tmp_deps) : NULL; + t->script = src->script ? strdup(src->script) : NULL; + t->info.line = src->info.line ? strdup(src->info.line) : NULL; + t->info.filename = src->info.filename ? strdup(src->info.filename) : NULL; + if (src->dependencies && src->dependencies->count_used) { + t->dependencies = target_list_new(src->dependencies->count_alloc); + if (!t->dependencies) { + fprintf(stderr, "unable to allocate memory to clone target dependencies\n"); + return NULL; + } + for (size_t i = 0; i < src->dependencies->count_used; i++) { + struct Target *src_target = src->dependencies->targets[i]; + target_list_add(t->dependencies, src_target); + } + } + return t; +} + +char *target_create_script_file(struct Target *t) { + char template[] = TARGET_SCRIPT_FILENAME_TEMPLATE; + if (mkstemps(template, 0) < 0) { + perror("mkstemps"); + return NULL; + } + return strdup(template); +} + +int target_run_all(struct Target *t, size_t *depth) { + int fail = 0; + + *depth += 1; + if (*depth > TARGET_RUN_MAX_DEPTH) { + fprintf(stderr, "maximum recursion depth reached: %d\n", TARGET_RUN_MAX_DEPTH); + if (t) { + fprintf(stderr, "%s: line %lu: %s\n", t->info.filename ? t->info.filename : "???", t->info.line_no, t->info.line); + } + *depth -= 1; + return -1; + } + + if (t && t->dependencies) { + for (size_t i = 0; i < t->dependencies->count_used; i++) { + struct Target *d = t->dependencies->targets[i]; + + if (target_run_all(d, depth)) { + fail = 1; + *depth -= 1; + break; + } + } + } + if (!fail) { + *depth -= 1; + return target_run(t, depth); + } + *depth -= 1; + return -1; +} + +int target_run(struct Target *t, const size_t *depth) { + if (!t || *depth > 100) { + return -1; + } + char *filename = target_create_script_file(t); + if (!filename) { + fprintf(stderr, "failed to create target script\n"); + return -1; + } + + if (chmod(filename, 0750) < 0) { + perror("chmod"); + safe_free(filename); + return -1; + } + + FILE *fp = fopen(filename, "w+"); + if (!fp) { + perror("unable to open target script for writing"); + remove(filename); + safe_free(filename); + return -1; + } + fprintf(fp, "%s", t->script ? t->script : ""); + fclose(fp); + + char *cmd = NULL; + if (asprintf(&cmd, "bash %s", filename) < 0) { + perror("asprintf"); + remove(filename); + safe_free(filename); + return -1; + } + + printf("==> Running target %s\n", t->id); + const int status = system(cmd); + remove(filename); + + safe_free(cmd); + safe_free(filename); + + return status; +} + +void target_free(struct Target **target) { + safe_free((*target)->id); + safe_free((*target)->_tmp_deps); + safe_free((*target)->script); + safe_free((*target)->info.line); + safe_free((*target)->info.filename); + if ((*target)->dependencies) { + // Dependencies are shared between lists. Do not wipe out the targets _here_. + safe_free((*target)->dependencies->targets); + safe_free((*target)->dependencies); + } + safe_free((*target)); +} + |
