From 0f6475b88466b6e4cd424f9807fa14eab0fafe96 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Tue, 29 Mar 2011 16:36:10 +0300 Subject: state, info: implement install_if (fixes #443) Implement the logic for install_if lines. Update info applet to also display the install_if related fields. --- src/info.c | 80 +++++++++++++++++++++++++++-- src/state.c | 165 +++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 185 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/info.c b/src/info.c index c9dc39c..3ae51f0 100644 --- a/src/info.c +++ b/src/info.c @@ -33,6 +33,8 @@ struct info_ctx { #define APK_INFO_RDEPENDS 0x10 #define APK_INFO_CONTENTS 0x20 #define APK_INFO_TRIGGERS 0x40 +#define APK_INFO_INSTALL_IF 0x80 +#define APK_INFO_RINSTALL_IF 0x100 static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity) { @@ -168,15 +170,22 @@ static void info_print_size(struct apk_package *pkg) static void info_print_depends(struct apk_package *pkg) { + apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); + char dep[256]; int i; - char *separator = apk_verbosity > 1 ? " " : "\n"; + if (apk_verbosity == 1) printf(PKG_VER_FMT " depends on:\n", PKG_VER_PRINTF(pkg)); if (apk_verbosity > 1) printf("%s: ", pkg->name->name); - for (i = 0; i < pkg->depends->num; i++) - printf("%s%s", pkg->depends->item[i].name->name, separator); + for (i = 0; i < pkg->depends->num; i++) { + apk_blob_t b = APK_BLOB_BUF(dep); + apk_blob_push_dep(&b, &pkg->depends->item[i]); + apk_blob_push_blob(&b, separator); + b = apk_blob_pushed(APK_BLOB_BUF(dep), b); + fwrite(b.ptr, b.len, 1, stdout); + } } static void info_print_required_by(struct apk_package *pkg) @@ -211,6 +220,58 @@ static void info_print_required_by(struct apk_package *pkg) } } +static void info_print_install_if(struct apk_package *pkg) +{ + apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); + char dep[256]; + int i; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " has auto-install rule:\n", + PKG_VER_PRINTF(pkg)); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + for (i = 0; i < pkg->install_if->num; i++) { + apk_blob_t b = APK_BLOB_BUF(dep); + apk_blob_push_dep(&b, &pkg->install_if->item[i]); + apk_blob_push_blob(&b, separator); + b = apk_blob_pushed(APK_BLOB_BUF(dep), b); + fwrite(b.ptr, b.len, 1, stdout); + } +} + +static void info_print_rinstall_if(struct apk_package *pkg) +{ + int i, j, k; + char *separator = apk_verbosity > 1 ? " " : "\n"; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " affects auto-installation of:\n", + PKG_VER_PRINTF(pkg)); + 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]; + + /* 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]; + + if (pkg0->ipkg == NULL) + 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; + } + } + } +} + static void info_print_contents(struct apk_package *pkg) { struct apk_installed_package *ipkg = pkg->ipkg; @@ -260,9 +321,12 @@ static void info_subaction(struct info_ctx *ctx, struct apk_package *pkg) info_print_required_by, info_print_contents, info_print_triggers, + info_print_install_if, + info_print_rinstall_if, }; const int requireipkg = - APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS; + APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS | + APK_INFO_RINSTALL_IF; int i; for (i = 0; i < ARRAY_SIZE(subactions); i++) { @@ -317,6 +381,12 @@ static int info_parse(void *ctx, struct apk_db_options *dbopts, case 'r': ictx->subaction_mask |= APK_INFO_RDEPENDS; break; + case 'I': + ictx->subaction_mask |= APK_INFO_INSTALL_IF; + break; + case 'i': + ictx->subaction_mask |= APK_INFO_RINSTALL_IF; + break; case 's': ictx->subaction_mask |= APK_INFO_SIZE; break; @@ -354,6 +424,8 @@ static struct apk_option info_options[] = { { 'W', "who-owns", "Print the package owning the specified file" }, { 'R', "depends", "List packages that the PACKAGE depends on" }, { 'r', "rdepends", "List all packages depending on PACKAGE" }, + { 'i', "install-if", "List the PACKAGE's install-if rule" }, + { 'I', "rinstall-if", "List all packages having install-if referencing PACKAGE" }, { 'w', "webpage", "Show URL for more information about PACKAGE" }, { 's', "size", "Show installed size of PACKAGE" }, { 'd', "description", "Print description for PACKAGE" }, diff --git a/src/state.c b/src/state.c index 6fa81f2..fef1cbb 100644 --- a/src/state.c +++ b/src/state.c @@ -238,6 +238,50 @@ void apk_state_unref(struct apk_state *state) free(state); } +static struct apk_package *get_locked_or_installed_package( + struct apk_state *state, + struct apk_name *name) +{ + int i; + + if (ns_locked(state->name[name->id])) + return ns_to_pkg(state->name[name->id]); + + if (!ns_empty(state->name[name->id])) { + struct apk_name_choices *ns = + ns_to_choices(state->name[name->id]); + + for (i = 0; i < ns->num; i++) { + if (ns->pkgs[i]->ipkg != NULL) + return ns->pkgs[i]; + } + return NULL; + } + + for (i = 0; i < name->pkgs->num; i++) { + if (name->pkgs->item[i]->ipkg != NULL) + return name->pkgs->item[i]; + } + return NULL; +} + +static int check_dependency_array(struct apk_state *state, + struct apk_dependency_array *da) +{ + struct apk_package *pkg; + int i; + + for (i = 0; i < da->num; i++) { + pkg = get_locked_or_installed_package(state, da->item[i].name); + if (pkg == NULL && da->item[i].result_mask != APK_DEPMASK_CONFLICT) + return 0; + if (!apk_dep_is_satisfied(&da->item[i], pkg)) + return 0; + } + + return da->num; +} + static int apk_state_add_change(struct apk_state *state, struct apk_package *oldpkg, struct apk_package *newpkg) @@ -340,20 +384,22 @@ int apk_state_prune_dependency(struct apk_state *state, return c->num; } -int apk_state_lock_dependency(struct apk_state *state, - struct apk_dependency *dep) +int apk_state_autolock_name(struct apk_state *state, struct apk_name *name, + int install_if) { - struct apk_name *name = dep->name; struct apk_name_choices *c; - struct apk_package *installed = NULL, *latest = NULL, *use; - int i, r; - - r = apk_state_prune_dependency(state, dep); - if (r <= 0) - return r; + struct apk_package *installed = NULL, *latest = NULL, *use; + int i; if (ns_pending(state->name[name->id])) return apk_state_lock_name(state, name, ns_to_pkg(state->name[name->id])); + if (ns_locked(state->name[name->id])) + return 0; + if (ns_empty(state->name[name->id])) { + /* This name has not been visited yet. + * Construct list of candidates. */ + state->name[name->id] = ns_from_choices(name_choices_new(state->db, name)); + } c = ns_to_choices(state->name[name->id]); #if 1 @@ -361,6 +407,10 @@ int apk_state_lock_dependency(struct apk_state *state, for (i = 0; i < c->num; i++) { struct apk_package *pkg = c->pkgs[i]; + if (install_if && + !check_dependency_array(state, pkg->install_if)) + continue; + if (pkg->ipkg != NULL) installed = pkg; else if (!apk_state_pkg_available(state, pkg)) @@ -402,7 +452,7 @@ int apk_state_lock_dependency(struct apk_state *state, use = latest; } if (use == NULL) - return -1; + return -2; return apk_state_lock_name(state, name, use); #else @@ -417,6 +467,18 @@ int apk_state_lock_dependency(struct apk_state *state, #endif } +int apk_state_lock_dependency(struct apk_state *state, + struct apk_dependency *dep) +{ + int r; + + r = apk_state_prune_dependency(state, dep); + if (r <= 0) + return r; + + return apk_state_autolock_name(state, dep->name, FALSE); +} + static int apk_state_fix_package(struct apk_state *state, struct apk_package *pkg) { @@ -438,7 +500,6 @@ static int apk_state_fix_package(struct apk_state *state, ret = -1; } } - return ret; } @@ -480,48 +541,19 @@ static int for_each_broken_reverse_depency(struct apk_state *state, void *ctx) { struct apk_package *pkg0; - int i, j, r; + int i, r; for (i = 0; i < name->rdepends->num; i++) { struct apk_name *name0 = name->rdepends->item[i]; - if (ns_locked(state->name[name0->id])) { - pkg0 = ns_to_pkg(state->name[name0->id]); - if (pkg0 == NULL) - continue; - r = call_if_dependency_broke(state, pkg0, name, - cb, ctx); - if (r != 0) - return r; - } else if (!ns_empty(state->name[name0->id])) { - struct apk_name_choices *ns = - ns_to_choices(state->name[name0->id]); - - for (j = 0; j < ns->num; j++) { - if (ns->pkgs[j]->ipkg == NULL) - continue; - r = call_if_dependency_broke(state, - ns->pkgs[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } else { - for (j = 0; j < name0->pkgs->num; j++) { - pkg0 = name0->pkgs->item[j]; - - if (pkg0->ipkg == NULL) - continue; + pkg0 = get_locked_or_installed_package(state, name0); + if (pkg0 == NULL) + continue; - r = call_if_dependency_broke(state, - name0->pkgs->item[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } + r = call_if_dependency_broke(state, pkg0, name, + cb, ctx); + if (r != 0) + return r; } return 0; @@ -591,15 +623,19 @@ int apk_state_lock_name(struct apk_state *state, } /* If the chosen package is installed, all is done here */ - if (oldpkg == newpkg && - (newpkg == NULL || - !(newpkg->name->flags & APK_NAME_REINSTALL))) - return 0; + if ((oldpkg != newpkg) || + (newpkg != NULL && (newpkg->name->flags & APK_NAME_REINSTALL))) { + /* Track change */ + r = apk_state_add_change(state, oldpkg, newpkg); + if (r != 0) + return r; + } - /* Track change */ - r = apk_state_add_change(state, oldpkg, newpkg); - if (r != 0) - return r; + /* Check all reverse install_if's */ + if (newpkg != NULL) { + for (i = 0; i < newpkg->name->rinstall_if->num; i++) + apk_state_autolock_name(state, newpkg->name->rinstall_if->item[i], TRUE); + } return 0; } @@ -809,6 +845,23 @@ static int apk_state_autoclean(struct apk_state *state, return r; } } + + for (i = 0; i < pkg->name->rinstall_if->num; i++) { + struct apk_name *n = pkg->name->rinstall_if->item[i]; + + if (ns_locked(state->name[n->id])) + continue; + if (n->flags & APK_NAME_TOPLEVEL) + continue; + + r = apk_state_autolock_name(state, n, TRUE); + if (r == -2) { + r = apk_state_lock_name(state, n, NULL); + if (r != 0) + return r; + } + } + return 0; } -- cgit v1.2.3-60-g2f50