git mirror - github.com/owenewans/holy - branch master
clone: https://src.holypkg.eu/holy/

file src/solve.c

#include "solve.h"

#include <solv/pool.h>
#include <solv/queue.h>
#include <solv/repo.h>
#include <solv/solvable.h>
#include <solv/solver.h>

#include <string.h>

static int solve(const struct holy_solver_item *items, size_t count,
                 const char *requested_id, int *selected, int unique, int all)
{
    Pool *pool = NULL;
    Repo *repo;
    Solver *solver = NULL;
    Queue jobs;
    Id requested = 0;
    size_t i, j;
    int rc = 0;
    if (selected && count && count <= 100000)
        memset(selected, 0, count * sizeof *selected);
    if (!items || !selected || (!all && (!requested_id || !*requested_id)) ||
        !count || count > 100000) return 0;
    for (i = 0; i < count; ++i) {
        if (!items[i].id || !*items[i].id ||
            (items[i].provides_count && !items[i].provides) ||
            (items[i].requires_count && !items[i].requires) ||
            (items[i].conflicts_count && !items[i].conflicts)) return 0;
        for (j = 0; j < i; ++j)
            if (!strcmp(items[i].id, items[j].id)) return 0;
    }
    pool = pool_create();
    if (!pool) return 0;
    repo = repo_create(pool, "holy-normalized");
    if (!repo) goto done;
    for (i = 0; i < count; ++i) {
        Id id = repo_add_solvable(repo);
        Solvable *s;
        if (!id) goto done;
        s = pool_id2solvable(pool, id);
        s->name = pool_str2id(pool, items[i].id, 1);
        s->evr = pool_str2id(pool, "0", 1);
        s->arch = pool_str2id(pool, "noarch", 1);
        if (!s->name || !s->evr || !s->arch) goto done;
        if (!all && !strcmp(items[i].id, requested_id)) requested = id;
        for (j = 0; j < items[i].provides_count; ++j) {
            Id capability;
            if (!items[i].provides[j] || !*items[i].provides[j]) goto done;
            capability = pool_str2id(pool, items[i].provides[j], 1);
            if (!capability) goto done;
            s->provides = repo_addid_dep(repo, s->provides, capability, 0);
        }
        for (j = 0; j < items[i].requires_count; ++j) {
            const struct holy_solver_requirement *req = &items[i].requires[j];
            Id dep, alternative;
            if (!req->first || !*req->first) goto done;
            dep = pool_str2id(pool, req->first, 1);
            if (!dep) goto done;
            if (req->alternative) {
                if (!*req->alternative) goto done;
                alternative = pool_str2id(pool, req->alternative, 1);
                if (!alternative) goto done;
                dep = pool_rel2id(pool, dep, alternative, REL_OR, 1);
                if (!dep) goto done;
            }
            s->requires = repo_addid_dep(repo, s->requires, dep, 0);
        }
        for (j = 0; j < items[i].conflicts_count; ++j) {
            Id dep;
            if (!items[i].conflicts[j] || !*items[i].conflicts[j]) goto done;
            dep = pool_str2id(pool, items[i].conflicts[j], 1);
            if (!dep) goto done;
            s->conflicts = repo_addid_dep(repo, s->conflicts, dep, 0);
        }
    }
    if (!all && !requested) goto done;
    repo_internalize(repo);
    pool_createwhatprovides(pool);
    solver = solver_create(pool);
    if (!solver) goto done;
    queue_init(&jobs);
    if (all) for (i = 0; i < count; ++i)
        queue_push2(&jobs, SOLVER_INSTALL | SOLVER_SOLVABLE, repo->start + (Id)i);
    else queue_push2(&jobs, SOLVER_INSTALL | SOLVER_SOLVABLE, requested);
    if (solver_solve(solver, &jobs)) rc = 2;
    else {
        for (i = 0; i < count; ++i)
            selected[i] = solver_get_decisionlevel(solver, repo->start + (Id)i) > 0;
        rc = 1;
        if (unique && !all) for (i = 0; i < count; ++i) {
            Solver *trial;
            int problems;
            if (!selected[i] || repo->start + (Id)i == requested) continue;
            queue_push2(&jobs, SOLVER_ERASE | SOLVER_SOLVABLE,
                        repo->start + (Id)i);
            trial = solver_create(pool);
            if (!trial) { rc = 0; queue_pop(&jobs); queue_pop(&jobs); break; }
            problems = solver_solve(trial, &jobs);
            solver_free(trial);
            queue_pop(&jobs);
            queue_pop(&jobs);
            if (!problems) { rc = 3; break; }
        }
        if (rc != 1) memset(selected, 0, count * sizeof *selected);
    }
    queue_free(&jobs);
done:
    if (solver) solver_free(solver);
    if (pool) pool_free(pool);
    return rc;
}

int holy_solve_exact(const struct holy_solver_item *items, size_t count,
                     const char *requested_id, int *selected)
{
    return solve(items, count, requested_id, selected, 0, 0);
}

int holy_solve_exact_unique(const struct holy_solver_item *items, size_t count,
                            const char *requested_id, int *selected)
{
    return solve(items, count, requested_id, selected, 1, 0);
}

int holy_solve_exact_set(const struct holy_solver_item *items, size_t count, int *selected)
{
    return solve(items, count, NULL, selected, 0, 1);
}