178 lines
3.6 KiB
C
178 lines
3.6 KiB
C
#include "target.h"
|
|
|
|
#include "log.h"
|
|
#include "service.h"
|
|
|
|
#include <errno.h>
|
|
#include <fx/collections/array.h>
|
|
#include <fx/collections/hashtable.h>
|
|
#include <fx/serial/ctx.h>
|
|
#include <fx/serial/toml.h>
|
|
#include <fx/string.h>
|
|
#include <fx/stringstream.h>
|
|
#include <magenta/log.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static struct queue targets = QUEUE_INIT;
|
|
|
|
struct queue *global_targets(void)
|
|
{
|
|
return &targets;
|
|
}
|
|
|
|
static int parse_target_data(fx_object *in, struct target *out)
|
|
{
|
|
if (!fx_object_is_type(in, FX_TYPE_HASHTABLE)) {
|
|
return -1;
|
|
}
|
|
|
|
const fx_value *target_v = fx_hashtable_get(in, &FX_CSTR("target"));
|
|
if (!target_v || !fx_value_is_type(target_v, FX_TYPE_HASHTABLE)) {
|
|
return -1;
|
|
}
|
|
fx_hashtable *in_target = NULL;
|
|
fx_value_get_object(target_v, &in_target);
|
|
|
|
const fx_value *unit_v = fx_hashtable_get(in, &FX_CSTR("unit"));
|
|
if (!unit_v || !fx_value_is_type(unit_v, FX_TYPE_HASHTABLE)) {
|
|
return -1;
|
|
}
|
|
fx_hashtable *in_unit = NULL;
|
|
fx_value_get_object(unit_v, &in_unit);
|
|
|
|
const fx_value *description_v
|
|
= fx_hashtable_get(in_unit, &FX_CSTR("description"));
|
|
if (!description_v
|
|
|| !fx_value_is_type(description_v, FX_TYPE_STRING)) {
|
|
return -1;
|
|
}
|
|
fx_string *description = NULL;
|
|
fx_value_get_object(description_v, &description);
|
|
|
|
const fx_value *deps_v
|
|
= fx_hashtable_get(in_target, &FX_CSTR("requires"));
|
|
if (deps_v && !fx_value_is_type(deps_v, FX_TYPE_ARRAY)) {
|
|
return -1;
|
|
}
|
|
fx_array *deps = NULL;
|
|
fx_value_get_object(deps_v, &deps);
|
|
|
|
int ret = 0;
|
|
size_t dep_count = fx_array_get_size(deps);
|
|
const fx_iterator *it = fx_iterator_begin(deps);
|
|
fx_foreach(dep, it)
|
|
{
|
|
if (!fx_value_is_type(dep, FX_TYPE_STRING)) {
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
fx_iterator_unref(it);
|
|
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
out->rl_requires_count = dep_count;
|
|
out->rl_requires = calloc(dep_count, sizeof(char *));
|
|
it = fx_iterator_begin(deps);
|
|
size_t i = 0;
|
|
fx_foreach(dep, it)
|
|
{
|
|
fx_string *str = NULL;
|
|
fx_value_get_object(dep, &str);
|
|
out->rl_requires[i++] = fx_string_steal(str);
|
|
}
|
|
fx_iterator_unref(it);
|
|
|
|
out->rl_description = fx_string_steal(description);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int target_load(const char *name, const char *path, struct target **out)
|
|
{
|
|
struct target *rl = malloc(sizeof *rl);
|
|
if (!rl) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
FILE *fp = fopen(path, "r");
|
|
if (!fp) {
|
|
free(rl);
|
|
return -1;
|
|
}
|
|
|
|
fx_stream *in = fx_stream_open_fp(fp);
|
|
fx_serial_ctx *ctx = fx_toml_serial_ctx_create();
|
|
fx_value data;
|
|
fx_result result = fx_serial_ctx_deserialise(ctx, in, &data, 0);
|
|
if (fx_result_is_error(result)) {
|
|
fx_throw(result);
|
|
free(rl);
|
|
errno = EFTYPE;
|
|
return -1;
|
|
}
|
|
|
|
if (!fx_value_is_type(&data, FX_TYPE_HASHTABLE)) {
|
|
free(rl);
|
|
errno = EFTYPE;
|
|
return -1;
|
|
}
|
|
|
|
if (parse_target_data(data.v_object, rl) != 0) {
|
|
free(rl);
|
|
errno = EFTYPE;
|
|
return -1;
|
|
}
|
|
|
|
rl->rl_name = fx_strdup(name);
|
|
|
|
fx_stream_unref(in);
|
|
fx_value_unset(&data);
|
|
|
|
fclose(fp);
|
|
|
|
*out = rl;
|
|
return 0;
|
|
}
|
|
|
|
struct target *target_find(const char *name)
|
|
{
|
|
struct queue_entry *cur = queue_first(&targets);
|
|
while (cur) {
|
|
struct target *rl
|
|
= QUEUE_CONTAINER(struct target, rl_entry, cur);
|
|
if (!strcmp(rl->rl_name, name)) {
|
|
return rl;
|
|
}
|
|
|
|
cur = queue_next(cur);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int target_activate(struct target *rl)
|
|
{
|
|
for (size_t i = 0; i < rl->rl_requires_count; i++) {
|
|
const char *svc_name = rl->rl_requires[i];
|
|
struct service *svc = service_find(svc_name);
|
|
if (!svc) {
|
|
log_fail("Cannot find service %s.", svc_name);
|
|
return -1;
|
|
}
|
|
|
|
int ret = service_start(svc);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
log_ok("Reached target %s.", rl->rl_description);
|
|
return 0;
|
|
}
|