diff options
author | Timo Teräs <timo.teras@iki.fi> | 2012-02-24 15:50:39 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2012-02-24 16:31:40 +0200 |
commit | 99145e2c0dc0b5b3b5a2a72fb1bff140d1f583f3 (patch) | |
tree | 37eb5b28d99600d3b310e502218dbc8167adf986 /src | |
parent | 97d44b5a002b61c7b95303bb8616f1caa6556bca (diff) | |
download | apk-tools-99145e2c0dc0b5b3b5a2a72fb1bff140d1f583f3.tar.gz apk-tools-99145e2c0dc0b5b3b5a2a72fb1bff140d1f583f3.tar.bz2 apk-tools-99145e2c0dc0b5b3b5a2a72fb1bff140d1f583f3.tar.xz apk-tools-99145e2c0dc0b5b3b5a2a72fb1bff140d1f583f3.zip |
all: introduce apk_provides and use it in apk_name
in preparation for provides support. implements also some
dependency satisfaction helper routines.
ref #574.
Diffstat (limited to 'src')
-rw-r--r-- | src/apk_database.h | 11 | ||||
-rw-r--r-- | src/apk_package.h | 10 | ||||
-rw-r--r-- | src/database.c | 19 | ||||
-rw-r--r-- | src/del.c | 67 | ||||
-rw-r--r-- | src/dot.c | 26 | ||||
-rw-r--r-- | src/fetch.c | 6 | ||||
-rw-r--r-- | src/fix.c | 9 | ||||
-rw-r--r-- | src/index.c | 8 | ||||
-rw-r--r-- | src/info.c | 77 | ||||
-rw-r--r-- | src/package.c | 85 | ||||
-rw-r--r-- | src/search.c | 21 | ||||
-rw-r--r-- | src/solver.c | 152 | ||||
-rw-r--r-- | src/ver.c | 28 |
13 files changed, 309 insertions, 210 deletions
diff --git a/src/apk_database.h b/src/apk_database.h index c9e1634..2dbf043 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -78,6 +78,15 @@ struct apk_db_dir_instance { gid_t gid; }; +#define PROVIDER_FMT "%s-"BLOB_FMT +#define PROVIDER_PRINTF(p) (p)->pkg->name->name, BLOB_PRINTF(*(p)->version) + +struct apk_provider { + struct apk_package *pkg; + apk_blob_t *version; +}; +APK_ARRAY(apk_provider_array, struct apk_provider); + struct apk_name { apk_hash_node hash_node; union { @@ -85,7 +94,7 @@ struct apk_name { void *state_ptr; }; char *name; - struct apk_package_array *pkgs; + struct apk_provider_array *providers; struct apk_name_array *rdepends; struct apk_name_array *rinstall_if; }; diff --git a/src/apk_package.h b/src/apk_package.h index 8321682..070caa8 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -18,6 +18,7 @@ struct apk_database; struct apk_name; +struct apk_provider; #define APK_SCRIPT_INVALID -1 #define APK_SCRIPT_PRE_INSTALL 0 @@ -103,6 +104,9 @@ struct apk_package { }; APK_ARRAY(apk_package_array, struct apk_package *); +#define APK_PROVIDER_FROM_PACKAGE(pkg) (struct apk_provider){(pkg),(pkg)->version} +#define APK_PROVIDER_FROM_PROVIDES(pkg,p) (struct apk_provider){(pkg),(p)->version} + #define PKG_VER_FMT "%s-" BLOB_FMT #define PKG_VER_PRINTF(pkg) pkg->name->name, BLOB_PRINTF(*pkg->version) @@ -121,7 +125,9 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t blob); void apk_dep_from_pkg(struct apk_dependency *dep, struct apk_database *db, struct apk_package *pkg); -int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg); +int apk_dep_is_materialized(struct apk_dependency *dep, struct apk_package *pkg); +int apk_dep_is_materialized_or_provided(struct apk_dependency *dep, struct apk_package *pkg); +int apk_dep_is_provided(struct apk_dependency *dep, struct apk_provider *p); void apk_blob_push_dep(apk_blob_t *to, struct apk_database *, struct apk_dependency *dep); void apk_blob_push_deps(apk_blob_t *to, struct apk_database *, struct apk_dependency_array *deps); @@ -137,6 +143,8 @@ void apk_deps_del(struct apk_dependency_array **deps, struct apk_name *name); int apk_script_type(const char *name); +struct apk_package *apk_pkg_get_installed(struct apk_name *name); + void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to); void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to); struct apk_package *apk_pkg_new(void); diff --git a/src/database.c b/src/database.c index 40f50aa..ed8b8ee 100644 --- a/src/database.c +++ b/src/database.c @@ -99,7 +99,7 @@ static apk_blob_t pkg_name_get_key(apk_hash_item item) static void pkg_name_free(struct apk_name *name) { free(name->name); - apk_package_array_free(&name->pkgs); + apk_provider_array_free(&name->providers); apk_name_array_free(&name->rdepends); apk_name_array_free(&name->rinstall_if); free(name); @@ -211,7 +211,7 @@ struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name) return NULL; pn->name = apk_blob_cstr(name); - apk_package_array_init(&pn->pkgs); + apk_provider_array_init(&pn->providers); apk_name_array_init(&pn->rdepends); apk_name_array_init(&pn->rinstall_if); apk_hash_insert_hashed(&db->available.names, pn, hash); @@ -529,7 +529,8 @@ struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package * if (idb == NULL) { idb = pkg; apk_hash_insert(&db->available.packages, pkg); - *apk_package_array_add(&pkg->name->pkgs) = pkg; + *apk_provider_array_add(&pkg->name->providers) = + APK_PROVIDER_FROM_PACKAGE(pkg); apk_db_pkg_rdepends(db, pkg); } else { idb->repos |= pkg->repos; @@ -1761,8 +1762,12 @@ static int foreach_cache_file(void *pctx, int dirfd, const char *name) char tmp[PATH_MAX]; if (name == NULL) goto no_pkg; - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; + + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg0 = name->providers->item[i].pkg; + + if (pkg0->name != name) + continue; apk_pkg_format_cache(pkg0, APK_BLOB_BUF(tmp)); if (apk_blob_compare(b, APK_BLOB_STR(tmp)) == 0) { @@ -2226,14 +2231,14 @@ static int apk_db_install_archive_entry(void *_ctx, break; /* Does the original package replace the new one? */ for (i = 0; i < opkg->ipkg->replaces->num; i++) { - if (apk_dep_is_satisfied(&opkg->ipkg->replaces->item[i], pkg)) { + if (apk_dep_is_materialized(&opkg->ipkg->replaces->item[i], pkg)) { opkg_prio = opkg->ipkg->replaces_priority; break; } } /* Does the new package replace the original one? */ for (i = 0; i < ctx->ipkg->replaces->num; i++) { - if (apk_dep_is_satisfied(&ctx->ipkg->replaces->item[i], opkg)) { + if (apk_dep_is_materialized(&ctx->ipkg->replaces->item[i], opkg)) { pkg_prio = ctx->ipkg->replaces_priority; break; } @@ -15,6 +15,11 @@ #include "apk_print.h" #include "apk_solver.h" +enum { + INSTALLED_PACKAGES, + MARKED_PACKAGES, +}; + struct del_ctx { int recursive_delete : 1; struct apk_dependency_array *world; @@ -35,7 +40,7 @@ static int del_parse(void *pctx, struct apk_db_options *db, return 0; } -static void foreach_installed_reverse_dependency( +static void foreach_package_reverse_dependency( struct apk_package *pkg, void (*cb)(struct apk_package *rdepend, void *ctx), void *ctx) { @@ -46,19 +51,18 @@ static void foreach_installed_reverse_dependency( return; name = pkg->name; - for (i = 0; i < pkg->name->rdepends->num; i++) { - struct apk_name *name0 = pkg->name->rdepends->item[i]; + for (i = 0; i < name->rdepends->num; i++) { + struct apk_name *name0 = name->rdepends->item[i]; - for (j = 0; j < name0->pkgs->num; j++) { - struct apk_package *pkg0 = name0->pkgs->item[j]; + for (j = 0; j < name0->providers->num; j++) { + struct apk_package *pkg0 = name0->providers->item[j].pkg; if (pkg0->ipkg == NULL) continue; for (k = 0; k < pkg0->depends->num; k++) { struct apk_dependency *dep = &pkg0->depends->item[k]; - if (dep->name == name && - apk_dep_is_satisfied(dep, pkg)) + if (apk_dep_is_materialized_or_provided(dep, pkg)) break; } if (k >= pkg0->depends->num) @@ -69,6 +73,24 @@ static void foreach_installed_reverse_dependency( } } +static void foreach_reverse_dependency( + struct apk_name *name, int mode, + void (*cb)(struct apk_package *rdepend, void *ctx), void *ctx) +{ + int i; + + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg0 = name->providers->item[i].pkg; + + if (mode == INSTALLED_PACKAGES && pkg0->ipkg == NULL) + continue; + else if (mode == MARKED_PACKAGES && pkg0->state_int == 0) + continue; + + foreach_package_reverse_dependency(pkg0, cb, ctx); + } +} + struct not_deleted_ctx { struct apk_indent indent; struct apk_package *pkg; @@ -82,7 +104,6 @@ static void print_not_deleted_message(struct apk_package *pkg, if (pkg == NULL) return; - if (pkg->state_ptr == ctx->pkg) return; pkg->state_ptr = ctx->pkg; @@ -97,19 +118,7 @@ static void print_not_deleted_message(struct apk_package *pkg, } apk_print_indented(&ctx->indent, APK_BLOB_STR(pkg->name->name)); - foreach_installed_reverse_dependency(pkg, print_not_deleted_message, pctx); -} - -static struct apk_package *name_to_pkg(struct apk_name *name) -{ - int i; - - for (i = 0; i < name->pkgs->num; i++) { - if (name->pkgs->item[i]->ipkg != NULL) - return name->pkgs->item[i]; - } - - return NULL; + foreach_package_reverse_dependency(pkg, print_not_deleted_message, pctx); } static void delete_from_world(struct apk_package *pkg, void *pctx) @@ -117,7 +126,7 @@ static void delete_from_world(struct apk_package *pkg, void *pctx) struct del_ctx *ctx = (struct del_ctx *) pctx; apk_deps_del(&ctx->world, pkg->name); - foreach_installed_reverse_dependency(pkg, delete_from_world, pctx); + foreach_package_reverse_dependency(pkg, delete_from_world, pctx); } static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) @@ -136,9 +145,9 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) name[i] = apk_db_get_name(db, APK_BLOB_STR(argv[i])); apk_deps_del(&ctx->world, name[i]); if (ctx->recursive_delete) - foreach_installed_reverse_dependency( - name_to_pkg(name[i]), - delete_from_world, ctx); + foreach_reverse_dependency( + name[i], INSTALLED_PACKAGES, + delete_from_world, ctx); } r = apk_solver_solve(db, 0, ctx->world, &solution, &changeset); @@ -147,14 +156,14 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) for (i = 0; i < solution->num; i++) { struct apk_package *pkg = solution->item[i].pkg; pkg->name->state_ptr = pkg; - pkg->state_int = 0; + pkg->state_int = 1; } for (i = 0; i < argc; i++) { ndctx.pkg = name[i]->state_ptr; ndctx.indent.indent = 0; - foreach_installed_reverse_dependency( - name[i]->state_ptr, - print_not_deleted_message, &ndctx); + foreach_reverse_dependency( + name[i], MARKED_PACKAGES, + print_not_deleted_message, &ndctx); if (ndctx.indent.indent) printf("\n"); } @@ -66,7 +66,7 @@ static int dump_pkg(struct dot_ctx *ctx, struct apk_package *pkg) struct apk_dependency *dep = &pkg->depends->item[i]; struct apk_name *name = dep->name; - if (name->pkgs->num == 0) { + if (name->providers->num == 0) { start_graph(ctx); printf(" \"" PKG_VER_FMT "\" -> \"%s\" [color=red];\n", PKG_VER_PRINTF(pkg), @@ -77,19 +77,27 @@ static int dump_pkg(struct dot_ctx *ctx, struct apk_package *pkg) name->state_int = 1; } } else { - for (j = 0; j < name->pkgs->num; j++) { - struct apk_package *pkg0 = name->pkgs->item[j]; + for (j = 0; j < name->providers->num; j++) { + struct apk_provider *p0 = &name->providers->item[j]; - if (!apk_dep_is_satisfied(dep, pkg0)) + if (!apk_dep_is_provided(dep, p0)) continue; - r = dump_pkg(ctx, pkg0); + r = dump_pkg(ctx, p0->pkg); ret += r; if (r || (!ctx->errors_only)) { start_graph(ctx); - printf(" \"" PKG_VER_FMT "\" -> \"" PKG_VER_FMT "\"%s;\n", + + if (p0->pkg->name != dep->name) { + /* provided package */ + printf(" \"" PROVIDER_FMT "\" -> \"" PKG_VER_FMT "\"[arrowhead=inv,color=green];\n", + PROVIDER_PRINTF(p0), + PKG_VER_PRINTF(p0->pkg)); + } + + printf(" \"" PKG_VER_FMT "\" -> \"" PROVIDER_FMT "\"%s;\n", PKG_VER_PRINTF(pkg), - PKG_VER_PRINTF(pkg0), + PROVIDER_PRINTF(p0), r ? "[color=red]" : ""); } } @@ -117,8 +125,8 @@ static int dot_main(void *pctx, struct apk_database *db, int argc, char **argv) struct apk_name *name = apk_db_get_name(db, APK_BLOB_STR(argv[i])); if (!name) continue; - for (j = 0; j < name->pkgs->num; j++) - dump_pkg(ctx, name->pkgs->item[j]); + for (j = 0; j < name->providers->num; j++) + dump_pkg(ctx, name->providers->item[j].pkg); } } else { apk_hash_foreach(&db->available.packages, foreach_pkg, pctx); diff --git a/src/fetch.c b/src/fetch.c index a9f2031..325249d 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -202,12 +202,12 @@ static int fetch_main(void *ctx, struct apk_database *db, int argc, char **argv) } else { struct apk_package *pkg = NULL; - for (j = 0; j < dep.name->pkgs->num; j++) + for (j = 0; j < dep.name->providers->num; j++) if (pkg == NULL || - apk_pkg_version_compare(dep.name->pkgs->item[j], + apk_pkg_version_compare(dep.name->providers->item[j].pkg, pkg) == APK_VERSION_GREATER) - pkg = dep.name->pkgs->item[j]; + pkg = dep.name->providers->item[j].pkg; if (pkg == NULL) { apk_message("Unable to get '%s'", dep.name->name); @@ -59,7 +59,7 @@ static int fix_main(void *pctx, struct apk_database *db, int argc, char **argv) struct fix_ctx *ctx = (struct fix_ctx *) pctx; struct apk_name *name; struct apk_package *pkg; - int r = 0, i, j; + int r = 0, i; if (!ctx->solver_flags) ctx->solver_flags = APK_SOLVERF_REINSTALL; @@ -83,12 +83,7 @@ static int fix_main(void *pctx, struct apk_database *db, int argc, char **argv) name = pkg->name; } else { name = apk_db_get_name(db, APK_BLOB_STR(argv[i])); - for (j = 0; j < name->pkgs->num; j++) { - if (name->pkgs->item[j]->ipkg != NULL) { - pkg = name->pkgs->item[j]; - break; - } - } + pkg = apk_pkg_get_installed(name); } if (pkg == NULL || pkg->ipkg == NULL) { apk_error("%s is not installed", name->name); diff --git a/src/index.c b/src/index.c index a3573f9..8d62252 100644 --- a/src/index.c +++ b/src/index.c @@ -72,7 +72,7 @@ static int warn_if_no_providers(apk_hash_item item, void *ctx) struct counts *counts = (struct counts *) ctx; struct apk_name *name = (struct apk_name *) item; - if (name->pkgs->num == 0) { + if (name->providers->num == 0) { if (++counts->unsatisfied < 10) { apk_warning("No provider for dependency '%s'", name->name); @@ -143,8 +143,10 @@ static int index_main(void *ctx, struct apk_database *db, int argc, char **argv) if (name == NULL) break; - for (j = 0; j < name->pkgs->num; j++) { - pkg = name->pkgs->item[j]; + for (j = 0; j < name->providers->num; j++) { + pkg = name->providers->item[j].pkg; + if (pkg->name != name) + continue; if (apk_blob_compare(bver, *pkg->version) != 0) continue; if (pkg->size != fi.size) @@ -69,7 +69,6 @@ static int info_exists(struct info_ctx *ctx, struct apk_database *db, int argc, char **argv) { struct apk_name *name; - struct apk_package *pkg = NULL; struct apk_dependency dep; int i, j, ok = 0; @@ -84,18 +83,14 @@ static int info_exists(struct info_ctx *ctx, struct apk_database *db, if (name == NULL) continue; - for (j = 0; j < name->pkgs->num; j++) { - pkg = name->pkgs->item[j]; - if (pkg->ipkg != NULL) - break; + for (j = 0; j < name->providers->num; j++) { + struct apk_provider *p = &name->providers->item[j]; + if (p->pkg->ipkg == NULL) + continue; + if (!apk_dep_is_provided(&dep, p)) + continue; + verbose_print_pkg(p->pkg, 0); } - if (j >= name->pkgs->num) - continue; - - if (!apk_dep_is_satisfied(&dep, pkg)) - continue; - - verbose_print_pkg(pkg, 0); ok++; } @@ -196,7 +191,7 @@ static void info_print_depends(struct apk_database *db, struct apk_package *pkg) static void info_print_required_by(struct apk_database *db, struct apk_package *pkg) { - int i, j, k; + int i, j; char *separator = apk_verbosity > 1 ? " " : "\n"; if (apk_verbosity == 1) @@ -205,23 +200,23 @@ static void info_print_required_by(struct apk_database *db, struct apk_package * if (apk_verbosity > 1) printf("%s: ", pkg->name->name); for (i = 0; i < pkg->name->rdepends->num; i++) { - struct apk_name *name0 = pkg->name->rdepends->item[i]; + struct apk_name *name0; + struct apk_package *pkg0; /* Check only the package that is installed, and that * it actually has this package as dependency. */ - for (j = 0; j < name0->pkgs->num; j++) { - struct apk_package *pkg0 = name0->pkgs->item[j]; + name0 = pkg->name->rdepends->item[i]; + pkg0 = apk_pkg_get_installed(name0); + if (pkg0 == NULL) + continue; - if (pkg0->ipkg == NULL) + for (j = 0; j < pkg0->depends->num; j++) { + if (pkg0->depends->item[j].name != pkg->name) continue; - for (k = 0; k < pkg0->depends->num; k++) { - if (pkg0->depends->item[k].name != pkg->name) - continue; - printf(PKG_VER_FMT "%s", - PKG_VER_PRINTF(pkg0), - separator); - break; - } + printf(PKG_VER_FMT "%s", + PKG_VER_PRINTF(pkg0), + separator); + break; } } } @@ -248,7 +243,7 @@ static void info_print_install_if(struct apk_database *db, struct apk_package *p static void info_print_rinstall_if(struct apk_database *db, struct apk_package *pkg) { - int i, j, k; + int i, j; char *separator = apk_verbosity > 1 ? " " : "\n"; if (apk_verbosity == 1) @@ -257,23 +252,23 @@ static void info_print_rinstall_if(struct apk_database *db, struct apk_package * if (apk_verbosity > 1) printf("%s: ", pkg->name->name); for (i = 0; i < pkg->name->rinstall_if->num; i++) { - struct apk_name *name0 = pkg->name->rinstall_if->item[i]; + struct apk_name *name0; + struct apk_package *pkg0; /* Check only the package that is installed, and that * it actually has this package in install_if. */ - for (j = 0; j < name0->pkgs->num; j++) { - struct apk_package *pkg0 = name0->pkgs->item[j]; + name0 = pkg->name->rinstall_if->item[i]; + pkg0 = apk_pkg_get_installed(name0); + if (pkg0 == NULL) + continue; - if (pkg0->ipkg == NULL) + for (j = 0; j < pkg0->install_if->num; j++) { + if (pkg0->install_if->item[j].name != pkg->name) continue; - for (k = 0; k < pkg0->install_if->num; k++) { - if (pkg0->install_if->item[k].name != pkg->name) - continue; - printf(PKG_VER_FMT "%s", - PKG_VER_PRINTF(pkg0), - separator); - break; - } + printf(PKG_VER_FMT "%s", + PKG_VER_PRINTF(pkg0), + separator); + break; } } } @@ -376,12 +371,12 @@ static int info_package(struct info_ctx *ctx, struct apk_database *db, for (i = 0; i < argc; i++) { name = apk_db_query_name(db, APK_BLOB_STR(argv[i])); - if (name == NULL || name->pkgs->num == 0) { + if (name == NULL || name->providers->num == 0) { apk_error("Not found: %s", argv[i]); return 1; } - for (j = 0; j < name->pkgs->num; j++) - info_subaction(ctx, name->pkgs->item[j]); + for (j = 0; j < name->providers->num; j++) + info_subaction(ctx, name->providers->item[j].pkg); } return 0; } diff --git a/src/package.c b/src/package.c index 5b89c0b..5446803 100644 --- a/src/package.c +++ b/src/package.c @@ -38,6 +38,21 @@ static const apk_spn_match_def apk_spn_dependency_separator = { [4] = (1<<0) /* */, }; +struct apk_package *apk_pkg_get_installed(struct apk_name *name) +{ + int i; + + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg = name->providers->item[i].pkg; + if (pkg->name != name) + continue; + if (pkg->ipkg == NULL) + continue; + return pkg; + } + return NULL; +} + void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to) { /* pkgname-1.0.apk */ @@ -311,7 +326,40 @@ void apk_dep_from_pkg(struct apk_dependency *dep, struct apk_database *db, }; } -int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg) +static int apk_dep_match_checksum(struct apk_dependency *dep, struct apk_package *pkg) +{ + struct apk_checksum csum; + apk_blob_t b = *dep->version; + + apk_blob_pull_csum(&b, &csum); + if (apk_checksum_compare(&csum, &pkg->csum) == 0) + return 1; + + return 0; +} + +int apk_dep_is_provided(struct apk_dependency *dep, struct apk_provider *p) +{ + if (p == NULL) + return dep->optional; + + switch (dep->result_mask) { + case APK_DEPMASK_CHECKSUM: + return apk_dep_match_checksum(dep, p->pkg); + case APK_DEPMASK_CONFLICT: + return 0; + case APK_DEPMASK_REQUIRE: + return 1; + default: + if (apk_version_compare_blob(*p->version, *dep->version) + & dep->result_mask) + return 1; + return 0; + } + return 0; +} + +int apk_dep_is_materialized(struct apk_dependency *dep, struct apk_package *pkg) { if (pkg == NULL) return dep->optional; @@ -319,15 +367,8 @@ int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg) return 0; switch (dep->result_mask) { - case APK_DEPMASK_CHECKSUM: { - struct apk_checksum csum; - apk_blob_t b = *dep->version; - - apk_blob_pull_csum(&b, &csum); - if (apk_checksum_compare(&csum, &pkg->csum) == 0) - return 1; - break; - } + case APK_DEPMASK_CHECKSUM: + return apk_dep_match_checksum(dep, pkg); case APK_DEPMASK_CONFLICT: return 0; case APK_DEPMASK_REQUIRE: @@ -336,11 +377,33 @@ int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg) if (apk_version_compare_blob(*pkg->version, *dep->version) & dep->result_mask) return 1; - break; + return 0; } return 0; } +int apk_dep_is_materialized_or_provided(struct apk_dependency *dep, struct apk_package *pkg) +{ + int i; + + if (pkg == NULL) + return dep->optional; + + if (dep->name == pkg->name) + return apk_dep_is_materialized(dep, pkg); + + for (i = 0; i < pkg->provides->num; i++) { + struct apk_provider p; + + if (pkg->provides->item[i].name != dep->name) + continue; + p = APK_PROVIDER_FROM_PROVIDES(pkg, &pkg->provides->item[i]); + return apk_dep_is_provided(dep, &p); + } + + return dep->optional; +} + void apk_blob_push_dep(apk_blob_t *to, struct apk_database *db, struct apk_dependency *dep) { int result_mask = dep->result_mask; diff --git a/src/search.c b/src/search.c index 0a158a7..e90076d 100644 --- a/src/search.c +++ b/src/search.c @@ -59,12 +59,12 @@ static void print_rdepends(struct search_ctx *ctx, struct apk_package *pkg) printf(PKG_VER_FMT ":", PKG_VER_PRINTF(pkg)); for (i = 0; i < name->rdepends->num; i++) { name0 = name->rdepends->item[i]; - for (j = 0; j < name0->pkgs->num; j++) { - pkg0 = name0->pkgs->item[j]; + + for (j = 0; j < name0->providers->num; j++) { + pkg0 = name0->providers->item[j].pkg; for (k = 0; k < pkg0->depends->num; k++) { dep = &pkg0->depends->item[k]; - if (name == dep->name && - apk_dep_is_satisfied(dep, pkg)) { + if (apk_dep_is_materialized_or_provided(dep, pkg)) { printf(" "); ctx->print_package(ctx, pkg0); } @@ -138,15 +138,16 @@ static int match_names(apk_hash_item item, void *ctx) } if (ictx->show_all) { - for (i = 0; i < name->pkgs->num; i++) - print_result(ictx, name->pkgs->item[i]); + for (i = 0; i < name->providers->num; i++) + print_result(ictx, name->providers->item[i].pkg); } else { struct apk_package *pkg = NULL; + apk_blob_t *version = NULL; - for (i = 0; i < name->pkgs->num; i++) { - if (pkg == NULL || - apk_pkg_version_compare(name->pkgs->item[i], pkg) == APK_VERSION_GREATER) - pkg = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + if (version == NULL || + apk_version_compare_blob(*name->providers->item[i].version, *version) == APK_VERSION_GREATER) + pkg = name->providers->item[i].pkg; } print_result(ictx, pkg); } diff --git a/src/solver.c b/src/solver.c index 9875dda..939676b 100644 --- a/src/solver.c +++ b/src/solver.c @@ -93,10 +93,12 @@ struct apk_package_state { unsigned locked : 1; }; +#define CHOSEN_NONE (struct apk_provider) { .pkg = NULL, .version = NULL } + struct apk_name_state { struct list_head unsolved_list; struct apk_name *name; - struct apk_package *chosen; + struct apk_provider chosen; struct apk_score minimum_penalty; unsigned short requirers; @@ -244,8 +246,8 @@ static struct apk_name_state *name_to_ns_alloc(struct apk_name *name) if (name->state_ptr == NULL) { ns = calloc(1, sizeof(struct apk_name_state)); ns->name = name; - for (i = 0; i < name->pkgs->num; i++) { - if (name->pkgs->item[i]->repos != 0) { + for (i = 0; i < name->providers->num; i++) { + if (name->providers->item[i].pkg->repos != 0) { ns->has_available_pkgs = 1; break; } @@ -282,14 +284,14 @@ static void foreach_dependency_pkg( struct apk_dependency *dep = &depends->item[i]; struct apk_name *name0 = dep->name; - for (j = 0; j < name0->pkgs->num; j++) { - struct apk_package *pkg0 = name0->pkgs->item[j]; + for (j = 0; j < name0->providers->num; j++) { + struct apk_provider *p0 = &name0->providers->item[j]; /* conflict depends on all to be not installed */ - if (!apk_dep_is_satisfied(dep, pkg0)) + if (!apk_dep_is_provided(dep, p0)) continue; - cb(ss, pkg0); + cb(ss, p0->pkg); } } } @@ -307,20 +309,21 @@ static void foreach_rinstall_if_pkg( dbg_printf(PKG_VER_FMT ": rinstall_if %s\n", PKG_VER_PRINTF(pkg), name0->name); - for (j = 0; j < name0->pkgs->num; j++) { - struct apk_package *pkg0 = name0->pkgs->item[j]; + for (j = 0; j < name0->providers->num; j++) { + struct apk_provider *p0 = &name0->providers->item[j]; + + for (k = 0; k < p0->pkg->install_if->num; k++) { + struct apk_dependency *dep = &p0->pkg->install_if->item[k]; - for (k = 0; k < pkg0->install_if->num; k++) { - struct apk_dependency *dep = &pkg0->install_if->item[k]; if (dep->name == name && - apk_dep_is_satisfied(dep, pkg)) + apk_dep_is_provided(dep, p0)) break; } - if (k >= pkg0->install_if->num) + if (k >= p0->pkg->install_if->num) continue; /* pkg depends (via install_if) on pkg0 */ - cb(ss, pkg0); + cb(ss, p0->pkg); } } } @@ -413,8 +416,8 @@ static int is_topology_optimum(struct apk_solver_state *ss, int i; get_topology_score(ss, ns, pkg, &score); - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg0 = name->providers->item[i].pkg; struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_score score0; @@ -434,9 +437,12 @@ static int is_topology_optimum(struct apk_solver_state *ss, } static int compare_absolute_package_preference( - struct apk_package *pkgA, - struct apk_package *pkgB) + struct apk_provider *pA, + struct apk_provider *pB) { + struct apk_package *pkgA = pA->pkg; + struct apk_package *pkgB = pB->pkg; + /* specified on command line directly */ if (pkgA->filename && !pkgB->filename) return 1; @@ -445,7 +451,7 @@ static int compare_absolute_package_preference( /* upgrading, or neither of the package is installed, so * we just fall back comparing to versions */ - switch (apk_pkg_version_compare(pkgA, pkgB)) { + switch (apk_version_compare_blob(*pA->version, *pB->version)) { case APK_VERSION_GREATER: return 1; case APK_VERSION_LESS: @@ -466,15 +472,17 @@ static void calculate_pkg_preference(struct apk_package *pkg) { struct apk_name *name = pkg->name; struct apk_package_state *ps = pkg_to_ps(pkg); + struct apk_provider p = APK_PROVIDER_FROM_PACKAGE(pkg); int i; - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; - if (pkg == pkg0) + for (i = 0; i < name->providers->num; i++) { + struct apk_provider *p0 = &name->providers->item[i]; + if (pkg == p0->pkg) continue; - if (compare_absolute_package_preference(pkg, pkg0) < 0) + if (compare_absolute_package_preference(&p, p0) < 0) ps->preference++; } + /* FIXME: consider all provided names too */ } static void count_name(struct apk_solver_state *ss, struct apk_name_state *ns) @@ -552,8 +560,8 @@ static void recalculate_maybe(struct apk_solver_state *ss, struct apk_name *name if (!propagate) return; - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg = name->providers->item[i].pkg; for (j = 0; j < pkg->depends->num; j++) { struct apk_dependency *dep = &pkg->depends->item[j]; @@ -573,8 +581,8 @@ static void sort_name(struct apk_solver_state *ss, struct apk_name *name) struct apk_name_state *ns = name_to_ns_alloc(name); int i; - for (i = 0; i < name->pkgs->num; i++) - sort_soft_dependencies(ss, name->pkgs->item[i]); + for (i = 0; i < name->providers->num; i++) + sort_soft_dependencies(ss, name->providers->item[i].pkg); count_name(ss, ns); recalculate_maybe(ss, name, @@ -602,7 +610,8 @@ static int install_if_missing(struct apk_solver_state *ss, struct apk_package *p /* ns can be NULL, if the install_if has a name with * no packages */ - if (ns == NULL || !ns->locked || !apk_dep_is_satisfied(dep, ns->chosen)) + if (ns == NULL || !ns->locked || + !apk_dep_is_provided(dep, &ns->chosen)) missing++; } @@ -615,7 +624,7 @@ static void get_unassigned_score(struct apk_name *name, struct apk_score *score) *score = (struct apk_score){ .conflicts = ns->requirers, - .preference = name->pkgs->num, + .preference = name->providers->num, }; } @@ -645,7 +654,7 @@ static void demote_name(struct apk_solver_state *ss, struct apk_name *name) /* remove cached information */ subscore(&ss->minimum_penalty, &ns->minimum_penalty); ns->minimum_penalty = (struct apk_score) { .score = 0 }; - ns->chosen = NULL; + ns->chosen = CHOSEN_NONE; /* and remove list, or request refresh */ if (ns->requirers == 0 && ns->install_ifs == 0) { @@ -791,7 +800,7 @@ static solver_result_t apply_decision(struct apk_solver_state *ss, } ss->assigned_names++; - ns->chosen = pkg; + ns->chosen = APK_PROVIDER_FROM_PACKAGE(pkg); list_del(&ns->unsolved_list); list_init(&ns->unsolved_list); @@ -811,7 +820,7 @@ static solver_result_t apply_decision(struct apk_solver_state *ss, get_unassigned_score(name, &score); addscore(&ss->score, &score); - ns->chosen = NULL; + ns->chosen = CHOSEN_NONE; ns->locked = 1; list_del(&ns->unsolved_list); list_init(&ns->unsolved_list); @@ -880,7 +889,7 @@ static void undo_decision(struct apk_solver_state *ss, } ns->locked = 0; - ns->chosen = NULL; + ns->chosen = CHOSEN_NONE; /* Put back the name to unsolved list */ promote_name(ss, name); @@ -974,17 +983,17 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency } if (ns->locked) { - if (ns->chosen) + if (ns->chosen.pkg) dbg_printf("%s: locked to " PKG_VER_FMT " already\n", - name->name, PKG_VER_PRINTF(ns->chosen)); + name->name, PKG_VER_PRINTF(ns->chosen.pkg)); else dbg_printf("%s: locked to empty\n", name->name); - if (!apk_dep_is_satisfied(dep, ns->chosen)) + if (!apk_dep_is_provided(dep, &ns->chosen)) ss->score.conflicts += strength; return; } - if (name->pkgs->num == 0) { + if (name->providers->num == 0) { if (!dep->optional) ss->score.conflicts += strength; return; @@ -1007,15 +1016,16 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency ns->last_touched_decision = ss->num_decisions; } - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + struct apk_provider *p0 = &name->providers->item[i]; + struct apk_package *pkg0 = p0->pkg; struct apk_package_state *ps0 = pkg_to_ps(pkg0); if (ps0 == NULL || ps0->locked || ss->topology_position < pkg0->topology_hard) continue; - if (!apk_dep_is_satisfied(dep, pkg0)) { + if (!apk_dep_is_provided(dep, p0)) { ps0->conflicts++; dbg_printf(PKG_VER_FMT ": conflicts++ -> %d\n", PKG_VER_PRINTF(pkg0), @@ -1044,18 +1054,18 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency * } if (ns->locked) { - if (ns->chosen != NULL) { + if (ns->chosen.pkg != NULL) { dbg_printf(PKG_VER_FMT " selected already for %s\n", - PKG_VER_PRINTF(ns->chosen), name->name); + PKG_VER_PRINTF(ns->chosen.pkg), name->name); } else { dbg_printf("%s selected to not be satisfied\n", name->name); } - if (!apk_dep_is_satisfied(dep, ns->chosen)) + if (!apk_dep_is_provided(dep, &ns->chosen)) ss->score.conflicts -= strength; return; } - if (name->pkgs->num == 0) { + if (name->providers->num == 0) { if (!dep->optional) ss->score.conflicts -= strength; return; @@ -1074,15 +1084,16 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency * ns->last_touched_decision = ss->num_decisions; } - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + struct apk_provider *p0 = &name->providers->item[i]; + struct apk_package *pkg0 = p0->pkg; struct apk_package_state *ps0 = pkg_to_ps(pkg0); if (ps0 == NULL || ps0->locked || ss->topology_position < pkg0->topology_hard) continue; - if (!apk_dep_is_satisfied(dep, pkg0)) { + if (!apk_dep_is_provided(dep, p0)) { ps0->conflicts--; dbg_printf(PKG_VER_FMT ": conflicts-- -> %d\n", PKG_VER_PRINTF(pkg0), @@ -1100,7 +1111,7 @@ static int reconsider_name(struct apk_solver_state *ss, struct apk_name *name) { struct apk_name_state *ns = name_to_ns(name); struct apk_score minscore, score; - struct apk_package *next_pkg = NULL; + struct apk_provider *next_p = NULL; unsigned int next_topology = 0, options = 0; int i, score_locked = FALSE; @@ -1124,8 +1135,9 @@ static int reconsider_name(struct apk_solver_state *ss, struct apk_name *name) minscore.score = -1; } - for (i = 0; i < name->pkgs->num; i++) { - struct apk_package *pkg0 = name->pkgs->item[i]; + for (i = 0; i < name->providers->num; i++) { + struct apk_provider *p0 = &name->providers->item[i]; + struct apk_package *pkg0 = p0->pkg; struct apk_package_state *ps0 = pkg_to_ps(pkg0); struct apk_score pkg0_score; @@ -1147,9 +1159,9 @@ static int reconsider_name(struct apk_solver_state *ss, struct apk_name *name) /* next in topology order - next to get locked in */ if (ps0->topology_soft < ss->topology_position && ps0->topology_soft > next_topology) - next_pkg = pkg0, next_topology = ps0->topology_soft; + next_p = p0, next_topology = ps0->topology_soft; else if (pkg0->topology_hard > next_topology) - next_pkg = pkg0, next_topology = pkg0->topology_hard; + next_p = p0, next_topology = pkg0->topology_hard; options++; } @@ -1164,15 +1176,15 @@ static int reconsider_name(struct apk_solver_state *ss, struct apk_name *name) } else if (options == 1 && score_locked && ns->none_excluded) { dbg_printf("reconsider_name: %s: only one choice left with known score, locking.\n", name->name); - return push_decision(ss, name, next_pkg, DECISION_ASSIGN, BRANCH_NO, FALSE); + return push_decision(ss, name, next_p->pkg, DECISION_ASSIGN, BRANCH_NO, FALSE); } - ns->chosen = next_pkg; + ns->chosen = *next_p; ns->minimum_penalty = minscore; addscore(&ss->minimum_penalty, &ns->minimum_penalty); dbg_printf("reconsider_name: %s: min penalty " SCORE_FMT ", next_pkg=%p\n", - name->name, SCORE_PRINTF(&minscore), next_pkg); + name->name, SCORE_PRINTF(&minscore), next_p->pkg); return SOLVERR_SOLUTION; } @@ -1197,11 +1209,11 @@ static int expand_branch(struct apk_solver_state *ss) return r; ns->name_touched = 0; } - if (pkg_to_ps(ns->chosen)->topology_soft < ss->topology_position && - pkg_to_ps(ns->chosen)->topology_soft > topology0) - pkg0 = ns->chosen, topology0 = pkg_to_ps(pkg0)->topology_soft; - else if (ns->chosen->topology_hard > topology0) - pkg0 = ns->chosen, topology0 = pkg0->topology_hard; + if (pkg_to_ps(ns->chosen.pkg)->topology_soft < ss->topology_position && + pkg_to_ps(ns->chosen.pkg)->topology_soft > topology0) + pkg0 = ns->chosen.pkg, topology0 = pkg_to_ps(pkg0)->topology_soft; + else if (ns->chosen.pkg->topology_hard > topology0) + pkg0 = ns->chosen.pkg, topology0 = pkg0->topology_hard; } if (pkg0 == NULL) { dbg_printf("expand_branch: solution with score "SCORE_FMT"\n", @@ -1355,15 +1367,15 @@ static int generate_changeset(struct apk_database *db, { struct apk_name *name; struct apk_name_state *ns; - struct apk_package *pkg, *pkg0; + struct apk_package *pkg; struct apk_installed_package *ipkg; - int i, j, num_installs = 0, num_removed = 0, ci = 0; + int i, num_installs = 0, num_removed = 0, ci = 0; /* calculate change set size */ for (i = 0; i < solution->num; i++) { pkg = solution->item[i].pkg; ns = name_to_ns(pkg->name); - ns->chosen = pkg; + ns->chosen = APK_PROVIDER_FROM_PACKAGE(pkg); ns->in_changeset = 1; if ((pkg->ipkg == NULL) || solution->item[i].reinstall || @@ -1373,7 +1385,7 @@ static int generate_changeset(struct apk_database *db, list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { name = ipkg->pkg->name; ns = name_to_ns(name); - if ((ns->chosen == NULL) || !ns->in_changeset) + if ((ns->chosen.pkg == NULL) || !ns->in_changeset) num_removed++; } @@ -1382,7 +1394,7 @@ static int generate_changeset(struct apk_database *db, list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { name = ipkg->pkg->name; ns = name_to_ns(name); - if ((ns->chosen == NULL) || !ns->in_changeset) { + if ((ns->chosen.pkg == NULL) || !ns->in_changeset) { changeset->changes->item[ci].oldpkg = ipkg->pkg; ci++; } @@ -1395,13 +1407,7 @@ static int generate_changeset(struct apk_database *db, if ((pkg->ipkg == NULL) || solution->item[i].reinstall || solution->item[i].repository_tag != pkg->ipkg->repository_tag){ - for (j = 0; j < name->pkgs->num; j++) { - pkg0 = name->pkgs->item[j]; - if (pkg0->ipkg == NULL) - continue; - changeset->changes->item[ci].oldpkg = pkg0; - break; - } + changeset->changes->item[ci].oldpkg = apk_pkg_get_installed(name); changeset->changes->item[ci].newpkg = pkg; changeset->changes->item[ci].repository_tag = solution->item[i].repository_tag; changeset->changes->item[ci].reinstall = solution->item[i].reinstall; @@ -1887,7 +1893,7 @@ static void print_dep_errors(struct apk_database *db, char *label, struct apk_de struct apk_dependency *dep = &deps->item[i]; struct apk_package *pkg = (struct apk_package*) dep->name->state_ptr; - if (apk_dep_is_satisfied(dep, pkg)) + if (apk_dep_is_materialized_or_provided(dep, pkg)) continue; if (print_label) { @@ -97,7 +97,6 @@ static int ver_parse(void *ctx, struct apk_db_options *dbopts, static void ver_print_package_status(struct ver_ctx *ictx, struct apk_database *db, struct apk_package *pkg) { struct apk_name *name; - struct apk_package *tmp; char pkgname[256]; const char *opstr; apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR("")); @@ -109,20 +108,20 @@ static void ver_print_package_status(struct ver_ctx *ictx, struct apk_database * allowed_repos = db->repo_tags[tag].allowed_repos; name = pkg->name; - for (i = 0; i < name->pkgs->num; i++) { - tmp = name->pkgs->item[i]; - if (tmp->name != name || tmp->repos == 0) + for (i = 0; i < name->providers->num; i++) { + struct apk_package *pkg0 = name->providers->item[i].pkg; + if (pkg0->name != name || pkg0->repos == 0) continue; - if (!(ictx->all_tags || (tmp->repos & allowed_repos))) + if (!(ictx->all_tags || (pkg0->repos & allowed_repos))) continue; - r = apk_version_compare_blob(*tmp->version, *latest); + r = apk_version_compare_blob(*pkg0->version, *latest); switch (r) { case APK_VERSION_GREATER: - latest = tmp->version; - latest_repos = tmp->repos; + latest = pkg0->version; + latest_repos = pkg0->repos; break; case APK_VERSION_EQUAL: - latest_repos |= tmp->repos; + latest_repos |= pkg0->repos; break; } } @@ -151,7 +150,8 @@ static int ver_main(void *ctx, struct apk_database *db, int argc, char **argv) struct ver_ctx *ictx = (struct ver_ctx *) ctx; struct apk_installed_package *ipkg; struct apk_name *name; - int i, j, ret = 0; + struct apk_package *pkg; + int i, ret = 0; if (ictx->limchars) { if (strlen(ictx->limchars) == 0) @@ -181,11 +181,9 @@ static int ver_main(void *ctx, struct apk_database *db, int argc, char **argv) ret = 1; goto ver_exit; } - for (j = 0; j < name->pkgs->num; j++) { - struct apk_package *pkg = name->pkgs->item[j]; - if (pkg->ipkg != NULL) - ver_print_package_status(ictx, db, pkg); - } + pkg = apk_pkg_get_installed(name); + if (pkg != NULL) + ver_print_package_status(ictx, db, pkg); } ver_exit: |