libopkg: implement lightweight package listing logic
[oweals/opkg-lede.git] / libopkg / pkg_depends.c
index 06519e1b3f3827308df8f30950aa4f1a1668c469..3abdcd38c4436468bed71929c7114ceb3dfacdc9 100644 (file)
@@ -100,17 +100,13 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
                        /* foreach possible satisfier */
                        for (j = 0; j < compound_depend->possibility_count; j++) {
                                /* foreach provided_by, which includes the abstract_pkg itself */
-                               abstract_pkg_t *abpkg =
-                                   possible_satisfiers[j]->pkg;
-                               abstract_pkg_vec_t *ab_provider_vec =
-                                   abpkg->provided_by;
+                               abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg;
+                               abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by;
                                int nposs = ab_provider_vec->len;
-                               abstract_pkg_t **ab_providers =
-                                   ab_provider_vec->pkgs;
+                               abstract_pkg_t **ab_providers = ab_provider_vec->pkgs;
                                int l;
                                for (l = 0; l < nposs; l++) {
-                                       pkg_vec_t *test_vec =
-                                           ab_providers[l]->pkgs;
+                                       pkg_vec_t *test_vec = ab_providers[l]->pkgs;
                                        /* if no depends on this one, try the first package that Provides this one */
                                        if (!test_vec) {        /* no pkg_vec hooked up to the abstract_pkg!  (need another feed?) */
                                                continue;
@@ -118,69 +114,45 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
 
                                        /* cruise this possiblity's pkg_vec looking for an installed version */
                                        for (k = 0; k < test_vec->len; k++) {
-                                               pkg_t *pkg_scout =
-                                                   test_vec->pkgs[k];
+                                               pkg_t *pkg_scout = test_vec->pkgs[k];
                                                /* not installed, and not already known about? */
-                                               if ((pkg_scout->state_want !=
-                                                    SW_INSTALL)
-                                                   && !pkg_scout->parent->
-                                                   dependencies_checked
-                                                   &&
-                                                   !is_pkg_in_pkg_vec
-                                                   (unsatisfied, pkg_scout)) {
+                                               if ((pkg_scout->state_want != SW_INSTALL)
+                                                   && !pkg_scout->parent->dependencies_checked
+                                                   && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) {
                                                        char **newstuff = NULL;
                                                        int rc;
-                                                       pkg_vec_t *tmp_vec =
-                                                           pkg_vec_alloc();
+                                                       pkg_vec_t *tmp_vec = pkg_vec_alloc();
                                                        /* check for not-already-installed dependencies */
-                                                       rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout, tmp_vec, &newstuff);
+                                                       rc = pkg_hash_fetch_unsatisfied_dependencies(
+                                                               pkg_scout, tmp_vec, &newstuff);
                                                        if (newstuff == NULL) {
                                                                int m;
                                                                int ok = 1;
-                                                               for (m = 0;
-                                                                    m < rc;
-                                                                    m++) {
-                                                                       pkg_t *p
-                                                                           =
-                                                                           tmp_vec->
-                                                                           pkgs
-                                                                           [m];
-                                                                       if (p->
-                                                                           state_want
-                                                                           ==
-                                                                           SW_INSTALL)
+                                                               for (m = 0; m < rc; m++) {
+                                                                       pkg_t *p = tmp_vec->pkgs[m];
+                                                                       if (p->state_want == SW_INSTALL)
                                                                                continue;
-                                                                       opkg_msg
-                                                                           (DEBUG,
+                                                                       opkg_msg(DEBUG,
                                                                             "Not installing %s due"
                                                                             " to requirement for %s.\n",
-                                                                            pkg_scout->
-                                                                            name,
-                                                                            p->
-                                                                            name);
+                                                                            pkg_scout->name, p->name);
                                                                        ok = 0;
                                                                        break;
                                                                }
-                                                               pkg_vec_free
-                                                                   (tmp_vec);
+                                                               pkg_vec_free(tmp_vec);
                                                                if (ok) {
                                                                        /* mark this one for installation */
-                                                                       opkg_msg
-                                                                           (NOTICE,
+                                                                       opkg_msg(NOTICE,
                                                                             "Adding satisfier for greedy"
                                                                             " dependence %s.\n",
-                                                                            pkg_scout->
-                                                                            name);
-                                                                       pkg_vec_insert
-                                                                           (unsatisfied,
-                                                                            pkg_scout);
+                                                                            pkg_scout->name);
+                                                                       pkg_vec_insert(unsatisfied, pkg_scout);
                                                                }
                                                        } else {
                                                                opkg_msg(DEBUG,
                                                                         "Not installing %s due to "
                                                                         "broken depends.\n",
-                                                                        pkg_scout->
-                                                                        name);
+                                                                        pkg_scout->name);
                                                                free(newstuff);
                                                        }
                                                }
@@ -194,15 +166,12 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
                /* foreach possible satisfier, look for installed package  */
                for (j = 0; j < compound_depend->possibility_count; j++) {
                        /* foreach provided_by, which includes the abstract_pkg itself */
-                       depend_t *dependence_to_satisfy =
-                           possible_satisfiers[j];
-                       abstract_pkg_t *satisfying_apkg =
-                           possible_satisfiers[j]->pkg;
+                       depend_t *dependence_to_satisfy = possible_satisfiers[j];
+                       abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
                        pkg_t *satisfying_pkg =
-                           pkg_hash_fetch_best_installation_candidate
-                           (satisfying_apkg,
-                            pkg_installed_and_constraint_satisfied,
-                            dependence_to_satisfy, 1);
+                               pkg_hash_fetch_best_installation_candidate(satisfying_apkg,
+                                       pkg_installed_and_constraint_satisfied,
+                                       dependence_to_satisfy, 1);
                        /* Being that I can't test constraing in pkg_hash, I will test it here */
                        if (satisfying_pkg != NULL) {
                                if (!pkg_installed_and_constraint_satisfied
@@ -222,20 +191,15 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
                        /* foreach possible satisfier, look for installed package  */
                        for (j = 0; j < compound_depend->possibility_count; j++) {
                                /* foreach provided_by, which includes the abstract_pkg itself */
-                               depend_t *dependence_to_satisfy =
-                                   possible_satisfiers[j];
-                               abstract_pkg_t *satisfying_apkg =
-                                   possible_satisfiers[j]->pkg;
+                               depend_t *dependence_to_satisfy = possible_satisfiers[j];
+                               abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
                                pkg_t *satisfying_pkg =
-                                   pkg_hash_fetch_best_installation_candidate
-                                   (satisfying_apkg,
-                                    pkg_constraint_satisfied,
-                                    dependence_to_satisfy, 1);
+                                       pkg_hash_fetch_best_installation_candidate(satisfying_apkg,
+                                               pkg_constraint_satisfied, dependence_to_satisfy, 1);
                                /* Being that I can't test constraing in pkg_hash, I will test it here too */
                                if (satisfying_pkg != NULL) {
-                                       if (!pkg_constraint_satisfied
-                                           (satisfying_pkg,
-                                            dependence_to_satisfy)) {
+                                       if (!pkg_constraint_satisfied(satisfying_pkg,
+                                                       dependence_to_satisfy)) {
                                                satisfying_pkg = NULL;
                                        }
                                }
@@ -243,16 +207,13 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
                                /* user request overrides package recommendation */
                                if (satisfying_pkg != NULL
                                    && (compound_depend->type == RECOMMEND
-                                       || compound_depend->type == SUGGEST)
-                                   && (satisfying_pkg->state_want ==
-                                       SW_DEINSTALL
-                                       || satisfying_pkg->state_want ==
-                                       SW_PURGE)) {
+                                           || compound_depend->type == SUGGEST)
+                                   && (satisfying_pkg->state_want == SW_DEINSTALL
+                                           || satisfying_pkg->state_want == SW_PURGE)) {
                                        opkg_msg(NOTICE,
                                                 "%s: ignoring recommendation for "
                                                 "%s at user request\n",
-                                                pkg->name,
-                                                satisfying_pkg->name);
+                                                pkg->name, satisfying_pkg->name);
                                        continue;
                                }
 
@@ -271,37 +232,28 @@ pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t * unsatisfied,
                                /* failure to meet recommendations is not an error */
                                if (compound_depend->type != RECOMMEND
                                    && compound_depend->type != SUGGEST)
-                                       the_lost =
-                                           add_unresolved_dep(pkg, the_lost,
-                                                              i);
+                                       the_lost = add_unresolved_dep(pkg, the_lost, i);
                                else
                                        opkg_msg(NOTICE,
-                                                "%s: unsatisfied recommendation for %s\n",
-                                                pkg->name,
-                                                compound_depend->
-                                                possibilities[0]->pkg->name);
+                                               "%s: unsatisfied recommendation for %s\n",
+                                               pkg->name,
+                                               compound_depend->possibilities[0]->pkg->name);
                        } else {
                                if (compound_depend->type == SUGGEST) {
                                        /* just mention it politely */
                                        opkg_msg(NOTICE,
-                                                "package %s suggests installing %s\n",
-                                                pkg->name,
-                                                satisfier_entry_pkg->name);
+                                               "package %s suggests installing %s\n",
+                                               pkg->name, satisfier_entry_pkg->name);
                                } else {
                                        char **newstuff = NULL;
 
                                        if (satisfier_entry_pkg != pkg &&
-                                           !is_pkg_in_pkg_vec(unsatisfied,
-                                                              satisfier_entry_pkg))
+                                           !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg))
                                        {
-                                               pkg_vec_insert(unsatisfied,
-                                                              satisfier_entry_pkg);
-                                               pkg_hash_fetch_unsatisfied_dependencies
-                                                   (satisfier_entry_pkg,
-                                                    unsatisfied, &newstuff);
-                                               the_lost =
-                                                   merge_unresolved(the_lost,
-                                                                    newstuff);
+                                               pkg_hash_fetch_unsatisfied_dependencies(
+                                                       satisfier_entry_pkg, unsatisfied, &newstuff);
+                                               pkg_vec_insert(unsatisfied, satisfier_entry_pkg);
+                                               the_lost = merge_unresolved(the_lost, newstuff);
                                                if (newstuff)
                                                        free(newstuff);
                                        }
@@ -390,21 +342,14 @@ pkg_vec_t *pkg_hash_fetch_conflicts(pkg_t * pkg)
                                                         "Internal error: pkg_scout=NULL\n");
                                                continue;
                                        }
-                                       if ((pkg_scout->state_status ==
-                                            SS_INSTALLED
-                                            || pkg_scout->state_want ==
-                                            SW_INSTALL)
-                                           &&
-                                           version_constraints_satisfied
-                                           (possible_satisfier, pkg_scout)
-                                           && !is_pkg_a_replaces(pkg_scout,
-                                                                 pkg)) {
-                                               if (!is_pkg_in_pkg_vec
-                                                   (installed_conflicts,
-                                                    pkg_scout)) {
-                                                       pkg_vec_insert
-                                                           (installed_conflicts,
-                                                            pkg_scout);
+                                       if ((pkg_scout->state_status == SS_INSTALLED
+                                                || pkg_scout->state_want == SW_INSTALL)
+                                               && version_constraints_satisfied(possible_satisfier,
+                                                       pkg_scout)
+                                               && !is_pkg_a_replaces(pkg_scout, pkg)) {
+                                               if (!is_pkg_in_pkg_vec(installed_conflicts,
+                                                       pkg_scout)) {
+                                                       pkg_vec_insert(installed_conflicts, pkg_scout);
                                                }
                                        }
                                }
@@ -477,34 +422,6 @@ int pkg_dependence_satisfiable(depend_t * depend)
        return 0;
 }
 
-int pkg_dependence_satisfied(depend_t * depend)
-{
-       abstract_pkg_t *apkg = depend->pkg;
-       abstract_pkg_vec_t *provider_apkgs = apkg->provided_by;
-       int n_providers = provider_apkgs->len;
-       abstract_pkg_t **apkgs = provider_apkgs->pkgs;
-       int i;
-       int n_pkgs;
-       int j;
-
-       for (i = 0; i < n_providers; i++) {
-               abstract_pkg_t *papkg = apkgs[i];
-               pkg_vec_t *pkg_vec = papkg->pkgs;
-               if (pkg_vec) {
-                       n_pkgs = pkg_vec->len;
-                       for (j = 0; j < n_pkgs; j++) {
-                               pkg_t *pkg = pkg_vec->pkgs[j];
-                               if (version_constraints_satisfied(depend, pkg)) {
-                                       if (pkg->state_status == SS_INSTALLED
-                                           || pkg->state_status == SS_UNPACKED)
-                                               return 1;
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
 static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg)
 {
        int i;
@@ -547,20 +464,14 @@ int pkg_replaces(pkg_t * pkg, pkg_t * replacee)
  */
 int pkg_conflicts_abstract(pkg_t * pkg, abstract_pkg_t * conflictee)
 {
-       compound_depend_t *conflicts, *conflict;
-
-       conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS);
+       int i, j;
+       compound_depend_t *conflicts;
 
-       int j;
-       for (conflict = conflicts; conflict->type; conflict++) {
-               int possibility_count = conflict->possibility_count;
-               struct depend **possibilities = conflict->possibilities;
-               for (j = 0; j < possibility_count; j++) {
-                       if (possibilities[j]->pkg == conflictee) {
+       for (conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS), i = 0; conflicts && conflicts[i].type; i++)
+               for (j = 0; j < conflicts[i].possibility_count; j++)
+                       if (conflicts[i].possibilities[j]->pkg == conflictee)
                                return 1;
-                       }
-               }
-       }
+
        return 0;
 }
 
@@ -570,27 +481,16 @@ int pkg_conflicts_abstract(pkg_t * pkg, abstract_pkg_t * conflictee)
  */
 int pkg_conflicts(pkg_t * pkg, pkg_t * conflictee)
 {
-       int j;
-       int possibility_count;
-       struct depend **possibilities;
-       compound_depend_t *conflicts, *conflict;
-       abstract_pkg_t **conflictee_provides, **provider, *possibility;
+       int i, j;
+       compound_depend_t *conflicts;
+       abstract_pkg_t **provider;
 
-       conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS);
-       conflictee_provides = pkg_get_ptr(conflictee, PKG_PROVIDES);
-
-       for (conflict = conflicts; conflict->type; conflict++) {
-               possibility_count = conflict->possibility_count;
-               possibilities = conflict->possibilities;
-               for (j = 0; j < possibility_count; j++) {
-                       possibility = possibilities[j]->pkg;
-                       for (provider = conflictee_provides; provider && *provider; provider++) {
-                               if (possibility == *provider) {
+       for (conflicts = pkg_get_ptr(pkg, PKG_CONFLICTS), i = 0; conflicts && conflicts[i].type; i++)
+               for (j = 0; j < conflicts[i].possibility_count; j++)
+                       for (provider = pkg_get_ptr(conflictee, PKG_PROVIDES); provider && *provider; provider++)
+                               if (conflicts[i].possibilities[j]->pkg == *provider)
                                        return 1;
-                               }
-                       }
-               }
-       }
+
        return 0;
 }
 
@@ -639,6 +539,30 @@ char **add_unresolved_dep(pkg_t * pkg, char **the_lost, int ref_ndx)
        return resized;
 }
 
+static void flag_related_packages(pkg_t *pkg, int state_flags)
+{
+       int i, j;
+       compound_depend_t *deps;
+
+       for (deps = pkg_get_ptr(pkg, PKG_DEPENDS), i = 0; deps && deps[i].type; i++)
+               for (j = 0; j < deps[i].possibility_count; j++) {
+                       if ((deps[i].possibilities[j]->pkg->state_flag & state_flags) != state_flags) {
+                               opkg_msg(DEBUG, "propagating pkg flag to dependent abpkg %s\n",
+                                        deps[i].possibilities[j]->pkg->name);
+                               deps[i].possibilities[j]->pkg->state_flag |= state_flags;
+                       }
+               }
+
+       for (deps = pkg_get_ptr(pkg, PKG_CONFLICTS), i = 0; deps && deps[i].type; i++)
+               for (j = 0; j < deps[i].possibility_count; j++) {
+                       if ((deps[i].possibilities[j]->pkg->state_flag & state_flags) != state_flags) {
+                               opkg_msg(DEBUG, "propagating pkg flag to conflicting abpkg %s\n",
+                                        deps[i].possibilities[j]->pkg->name);
+                               deps[i].possibilities[j]->pkg->state_flag |= state_flags;
+                       }
+               }
+}
+
 abstract_pkg_t **init_providelist(pkg_t *pkg, int *count)
 {
        abstract_pkg_t *ab_pkg;
@@ -659,7 +583,8 @@ abstract_pkg_t **init_providelist(pkg_t *pkg, int *count)
                if (!ab_pkg->pkgs)
                        ab_pkg->pkgs = pkg_vec_alloc();
 
-               abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg);
+               if (!abstract_pkg_vec_contains(ab_pkg->provided_by, ab_pkg))
+                       abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg);
 
                provides[0] = ab_pkg;
                provides[1] = NULL;
@@ -670,10 +595,20 @@ abstract_pkg_t **init_providelist(pkg_t *pkg, int *count)
                pkg_set_ptr(pkg, PKG_PROVIDES, provides);
        }
        else if (count) {
-               for (*count = 1; *provides; provides++)
+               for (*count = 1; *provides; provides++) {
+                       if (pkg->state_flag & SF_NEED_DETAIL) {
+                               if (!((*provides)->state_flag & SF_NEED_DETAIL)) {
+                                       opkg_msg(DEBUG, "propagating pkg flag to provided abpkg %s\n",
+                                                (*provides)->name);
+                                       (*provides)->state_flag |= SF_NEED_DETAIL;
+                               }
+                       }
                        (*count)++;
+               }
        }
 
+       flag_related_packages(pkg, SF_NEED_DETAIL);
+
        return provides;
 }
 
@@ -698,7 +633,16 @@ void parse_providelist(pkg_t *pkg, char *list)
 
                provided_abpkg = ensure_abstract_pkg_by_name(item);
 
-               abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg);
+               if (provided_abpkg->state_flag & SF_NEED_DETAIL) {
+                       if (!(ab_pkg->state_flag & SF_NEED_DETAIL)) {
+                               opkg_msg(DEBUG, "propagating provided abpkg flag to "
+                                               "provider abpkg %s\n", ab_pkg->name);
+                               ab_pkg->state_flag |= SF_NEED_DETAIL;
+                       }
+               }
+
+               if (!abstract_pkg_vec_contains(provided_abpkg->provided_by, ab_pkg))
+                       abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg);
 
                provides = tmp;
                provides[count - 1] = provided_abpkg;
@@ -722,9 +666,8 @@ void parse_replacelist(pkg_t *pkg, char *list)
 
        abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg);
 
-       for (count = 1, item = strtok_r(list, ", ", &tok);
-            item;
-            count++, item = strtok_r(NULL, ", ", &tok), count++) {
+       for (count = 1, item = strtok_r(list, ", ", &tok); item;
+            count++, item = strtok_r(NULL, ", ", &tok)) {
                tmp = realloc(replaces, sizeof(abstract_pkg_t *) * (count + 1));
 
                if (!tmp)
@@ -732,14 +675,24 @@ void parse_replacelist(pkg_t *pkg, char *list)
 
                old_abpkg = ensure_abstract_pkg_by_name(item);
 
+               if (pkg->state_flag & SF_NEED_DETAIL) {
+                       if (!(old_abpkg->state_flag & SF_NEED_DETAIL)) {
+                               opkg_msg(DEBUG, "propagating pkg flag to replaced abpkg %s\n",
+                                        old_abpkg->name);
+                               old_abpkg->state_flag |= SF_NEED_DETAIL;
+                       }
+               }
+
                if (!old_abpkg->replaced_by)
                        old_abpkg->replaced_by = abstract_pkg_vec_alloc();
 
                /* if a package pkg both replaces and conflicts old_abpkg,
                 * then add it to the replaced_by vector so that old_abpkg
                 * will be upgraded to ab_pkg automatically */
-               if (pkg_conflicts_abstract(pkg, old_abpkg))
-                       abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg);
+               if (pkg_conflicts_abstract(pkg, old_abpkg)) {
+                       if (!abstract_pkg_vec_contains(old_abpkg->replaced_by, ab_pkg))
+                               abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg);
+               }
 
                replaces = tmp;
                replaces[count - 1] = old_abpkg;