Skip to content
Snippets Groups Projects
parse_frontend.c 6.99 KiB
/*
 * parse_frontend.c
 *
 * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
 *
 * All rights reserved.
 *
 * This file is part of Obarun. It is subject to the license terms in
 * the LICENSE file found in the top-level directory of this
 * distribution.
 * This file may not be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file./
 */

#include <stdint.h>
#include <string.h>
#include <stdlib.h> //free

#include <oblibs/log.h>
#include <oblibs/sastr.h>
#include <oblibs/string.h>
#include <oblibs/types.h>
#include <oblibs/environ.h>

#include <skalibs/stralloc.h>

#include <66/utils.h>
#include <66/constants.h>
#include <66/ssexec.h>
#include <66/service.h>
#include <66/tree.h>
#include <66/config.h>
#include <66/resolve.h>
#include <66/environ.h>
#include <66/enum.h>
#include <66/state.h> // service_is_g flag
#include <66/parser.h>

static void parse_service_instance(stralloc *frontend, char const *svsrc, char const *sv, int insta)
{
    log_flow() ;

    stralloc sa = STRALLOC_ZERO ;

    if (!instance_splitname(&sa, sv, insta, SS_INSTANCE_TEMPLATE))
        log_die(LOG_EXIT_SYS, "split instance service of: ", sv) ;

    log_trace("read frontend service of: ", svsrc, sv) ;

    if (read_svfile(frontend, sa.s, svsrc) <= 0)
        log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", svsrc, sa.s) ;

    stralloc_free(&sa) ;

    if (!instance_create(frontend, sv, SS_INSTANCE_REGEX, insta))
        log_die(LOG_EXIT_SYS, "create instance service: ", sv) ;

}

/* @sv -> name of the service to parse with
 * the path of the frontend file source
 * @Die on fail
 * @Return 1 on success
 * @Return 2 -> already parsed */
int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, unsigned int *residx, char const *forced_directory, char const *main)
{
    log_flow() ;

    int insta, r, isparsed ;
    size_t svlen = strlen(sv) ;
    char svname[svlen + 1], svsrc[svlen + 1] ;
    char atree[SS_MAX_TREENAME + 1] ;
    stralloc sa = STRALLOC_ZERO ;

    if (!ob_basename(svname, sv))
        log_dieu(LOG_EXIT_SYS, "get basename of: ", sv) ;

    if (!ob_dirname(svsrc, sv))
        log_dieu(LOG_EXIT_SYS, "get dirname of: ", sv) ;

    if (service_resolve_array_search(ares, *areslen, svname) >= 0)
        log_warn_return(2, "ignoring: ", svname, " service -- already appended to the selection") ;

    log_trace("parse service: ", sv) ;

    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;

    resolve_init(wres) ;

    insta = instance_check(svname) ;

    if (insta > 0) {

        parse_service_instance(&sa, svsrc, svname, insta) ;

    } else {

        log_trace("read frontend service of: ", sv) ;

        if (read_svfile(&sa, svname, svsrc) <= 0)
            log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", sv) ;
    }

    char file[sa.len + 1] ;
    auto_strings(file, sa.s) ;

    isparsed = service_is_g(atree, svname, STATE_FLAGS_ISPARSED) ;
    if (isparsed == -1)
        log_dieusys(LOG_EXIT_SYS, "get information of service: ", svname, " -- please make a bug report") ;

    if (isparsed && !force) {

            log_warn("ignoring service: ", svname, " -- already parsed") ;
            return 2 ;
    }

    if (info->opt_tree) {

        r = tree_isvalid(info->base.s, info->treename.s) ;
        if (r < 0)
            log_dieu(LOG_EXIT_SYS, "check validity of tree: ", info->treename.s) ;

        if (!r) {

            /** @intree may not exist */
            r = sastr_find(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_INTREE)) ;
            if (r == -1)
                goto follow ;

            if (!environ_get_val_of_key(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_INTREE)))
                log_dieu(LOG_EXIT_SYS, "get field intree of service: ", sv) ;

            if (!sastr_clean_element(&sa))
                log_dieu(LOG_EXIT_SYS, "clean field intree of service: ", sv) ;

            res.intree = resolve_add_string(wres, sa.s) ;

            info->treename.len = 0 ;
            sa.len = 0 ;
            if (!auto_stra(&info->treename, res.sa.s + res.intree) ||
                !auto_stra(&sa, file))
                    log_die_nomem("stralloc") ;
        }
    }

    follow:

    if (!environ_get_val_of_key(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_TYPE)))
        log_dieu(LOG_EXIT_SYS, "get field ", get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_TYPE)," of service: ", svname) ;

    char store[sa.len + 1] ;
    auto_strings(store, sa.s) ;

    if (!parse_store_main(&res, store, SECTION_MAIN, KEY_MAIN_TYPE))
        log_dieu(LOG_EXIT_SYS, "store field type of service: ", svname) ;

    res.name = resolve_add_string(wres, svname) ;

    res.owner = info->owner ;
    res.ownerstr = resolve_add_string(wres, info->ownerstr) ;

    res.path.frontend = resolve_add_string(wres, sv) ;

    // keep overwrite_conf
    res.environ.env_overwrite = conf ;

    /** try to create the tree if not exist yet with
     * the help of the seed files */
    set_treeinfo(info) ;

    /** contents of directory should be listed by service_frontend_path
     * except for module type */
    if (scan_mode(sv,S_IFDIR) == 1 && res.type != TYPE_MODULE)
        goto freed ;

    if (!parse_contents(wres, file, svname))
        log_dieu(LOG_EXIT_SYS, "parse file of service: ", svname) ;

    if (!parse_mandatory(&res))
        log_die(LOG_EXIT_SYS, "some mandatory field is missing for service: ", svname) ;

    /** append res.dependencies.depends list with the optional dependencies list */
    if (res.dependencies.noptsdeps) {

        if (res.dependencies.ndepends) {
            size_t len = strlen(res.sa.s + res.dependencies.depends) ;
            char t[len + strlen(res.sa.s + res.dependencies.optsdeps) + 2] ;
            auto_strings(t + len, " ", res.sa.s + res.dependencies.optsdeps) ;
            res.dependencies.depends = resolve_add_string(wres, t) ;

        } else {

            res.dependencies.depends = resolve_add_string(wres, res.sa.s + res.dependencies.optsdeps) ;
        }
        res.dependencies.ndepends += res.dependencies.noptsdeps ;
    }

    /** We take the dependencies in two case:
     * If the user ask for it(force > 1)
     * If the service was never parsed(!isparsed)*/
    if (force > 1 || !isparsed)
        if (!parse_dependencies(&res, ares, areslen, info, force, conf, forced_directory, main))
            log_dieu(LOG_EXIT_SYS, "parse dependencies of service: ", svname) ;

    if (res.type == TYPE_MODULE)
        parse_module(&res, ares, areslen, info, force) ;

    log_trace("add service ", svname, " to the selection: ") ;
    if (service_resolve_array_search(ares, *areslen, svname) < 0) {
        if (*areslen >= SS_MAX_SERVICE)
            log_die(LOG_EXIT_SYS, "too many services to parse -- compile again 66 changing the --max-service options") ;
        (*residx) = *areslen ;
        ares[(*areslen)++] = res ;
    }

    freed:
        stralloc_free(&sa) ;
        free(wres) ;
        return 1 ;
}