static void pk_backend_transaction_process_new_optdepends (PkBackend *self, alpm_pkg_t *pkg, alpm_pkg_t *old) { alpm_list_t *optdepends; const alpm_list_t *i; g_return_if_fail (self != NULL); g_return_if_fail (pkg != NULL); g_return_if_fail (old != NULL); optdepends = alpm_list_diff (alpm_pkg_get_optdepends (pkg), alpm_pkg_get_optdepends (old), alpm_depend_compare); if (optdepends == NULL) { return; } pk_backend_output (self, "New optional dependencies:\n"); for (i = optdepends; i != NULL; i = i->next) { gchar *depend = alpm_dep_compute_string (i->data); gchar *output = g_strdup_printf ("%s\n", depend); free (depend); pk_backend_output (self, output); g_free (output); } alpm_list_free (optdepends); }
/* Convert a list of alpm_pkg_t * to a graph structure, * with a edge for each dependency. * Returns a list of vertices (one vertex = one package) * (used by alpm_sortbydeps) */ static alpm_list_t *dep_graph_init(alpm_handle_t *handle, alpm_list_t *targets, alpm_list_t *ignore) { alpm_list_t *i, *j; alpm_list_t *vertices = NULL; alpm_list_t *localpkgs = alpm_list_diff( alpm_db_get_pkgcache(handle->db_local), ignore, ptr_cmp); /* We create the vertices */ for(i = targets; i; i = i->next) { alpm_graph_t *vertex = _alpm_graph_new(); vertex->data = (void *)i->data; vertices = alpm_list_add(vertices, vertex); } /* We compute the edges */ for(i = vertices; i; i = i->next) { alpm_graph_t *vertex_i = i->data; alpm_pkg_t *p_i = vertex_i->data; /* TODO this should be somehow combined with alpm_checkdeps */ for(j = vertices; j; j = j->next) { alpm_graph_t *vertex_j = j->data; alpm_pkg_t *p_j = vertex_j->data; if(_alpm_pkg_depends_on(p_i, p_j)) { vertex_i->children = alpm_list_add(vertex_i->children, vertex_j); } } /* lazily add local packages to the dep graph so they don't * get resolved unnecessarily */ j = localpkgs; while(j) { alpm_list_t *next = j->next; if(_alpm_pkg_depends_on(p_i, j->data)) { alpm_graph_t *vertex_j = _alpm_graph_new(); vertex_j->data = (void *)j->data; vertices = alpm_list_add(vertices, vertex_j); vertex_i->children = alpm_list_add(vertex_i->children, vertex_j); localpkgs = alpm_list_remove_item(localpkgs, j); free(j); } j = next; } vertex_i->childptr = vertex_i->children; } alpm_list_free(localpkgs); return vertices; }
/** * @brief Returns a list of conflicts between a db and a list of packages. */ alpm_list_t *_alpm_outerconflicts(alpm_db_t *db, alpm_list_t *packages) { alpm_list_t *baddeps = NULL; if(db == NULL) { return NULL; } alpm_list_t *dblist = alpm_list_diff(_alpm_db_get_pkgcache(db), packages, _alpm_pkg_cmp); /* two checks to be done here for conflicts */ _alpm_log(db->handle, ALPM_LOG_DEBUG, "check targets vs db\n"); check_conflict(db->handle, packages, dblist, &baddeps, 1); _alpm_log(db->handle, ALPM_LOG_DEBUG, "check db vs targets\n"); check_conflict(db->handle, dblist, packages, &baddeps, -1); alpm_list_free(dblist); return baddeps; }
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) { alpm_list_t *i, *j; alpm_list_t *deps = NULL; alpm_list_t *unresolvable = NULL; int from_sync = 0; int ret = 0; alpm_trans_t *trans = handle->trans; alpm_event_t event; if(data) { *data = NULL; } for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; if (spkg->origin == ALPM_PKG_FROM_SYNCDB){ from_sync = 1; break; } } /* ensure all sync database are valid if we will be using them */ for(i = handle->dbs_sync; i; i = i->next) { const alpm_db_t *db = i->data; if(db->status & DB_STATUS_INVALID) { RET_ERR(handle, ALPM_ERR_DB_INVALID, -1); } /* missing databases are not allowed if we have sync targets */ if(from_sync && db->status & DB_STATUS_MISSING) { RET_ERR(handle, ALPM_ERR_DB_NOT_FOUND, -1); } } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { alpm_list_t *resolved = NULL; alpm_list_t *remove = alpm_list_copy(trans->remove); alpm_list_t *localpkgs; /* Build up list by repeatedly resolving each transaction package */ /* Resolve targets dependencies */ event.type = ALPM_EVENT_RESOLVEDEPS_START; EVENT(handle, &event); _alpm_log(handle, ALPM_LOG_DEBUG, "resolving target's dependencies\n"); /* build remove list for resolvedeps */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; for(j = spkg->removes; j; j = j->next) { remove = alpm_list_add(remove, j->data); } } /* Compute the fake local database for resolvedeps (partial fix for the * phonon/qt issue) */ localpkgs = alpm_list_diff(_alpm_db_get_pkgcache(handle->db_local), trans->add, _alpm_pkg_cmp); /* Resolve packages in the transaction one at a time, in addition building up a list of packages which could not be resolved. */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(_alpm_resolvedeps(handle, localpkgs, pkg, trans->add, &resolved, remove, data) == -1) { unresolvable = alpm_list_add(unresolvable, pkg); } /* Else, [resolved] now additionally contains [pkg] and all of its dependencies not already on the list */ } alpm_list_free(localpkgs); alpm_list_free(remove); /* If there were unresolvable top-level packages, prompt the user to see if they'd like to ignore them rather than failing the sync */ if(unresolvable != NULL) { alpm_question_remove_pkgs_t question = { .type = ALPM_QUESTION_REMOVE_PKGS, .skip = 0, .packages = unresolvable }; QUESTION(handle, &question); if(question.skip) { /* User wants to remove the unresolvable packages from the transaction. The packages will be removed from the actual transaction when the transaction packages are replaced with a dependency-reordered list below */ handle->pm_errno = 0; if(data) { alpm_list_free_inner(*data, (alpm_list_fn_free)alpm_depmissing_free); alpm_list_free(*data); *data = NULL; } } else { /* pm_errno was set by resolvedeps, callback may have overwrote it */ handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS; alpm_list_free(resolved); alpm_list_free(unresolvable); ret = -1; goto cleanup; } } /* Set DEPEND reason for pulled packages */ for(i = resolved; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(!alpm_pkg_find(trans->add, pkg->name)) { pkg->reason = ALPM_PKG_REASON_DEPEND; } } /* Unresolvable packages will be removed from the target list; set these * aside in the transaction as a list we won't operate on. If we free them * before the end of the transaction, we may kill pointers the frontend * holds to package objects. */ trans->unresolvable = unresolvable; alpm_list_free(trans->add); trans->add = resolved; event.type = ALPM_EVENT_RESOLVEDEPS_DONE; EVENT(handle, &event); }
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) { alpm_list_t *i, *j; alpm_list_t *deps = NULL; alpm_list_t *unresolvable = NULL; alpm_list_t *remove = NULL; int ret = 0; alpm_trans_t *trans = handle->trans; if(data) { *data = NULL; } /* ensure all sync database are valid since we will be using them */ for(i = handle->dbs_sync; i; i = i->next) { const alpm_db_t *db = i->data; if(!(db->status & DB_STATUS_VALID)) { RET_ERR(handle, ALPM_ERR_DB_INVALID, -1); } } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { alpm_list_t *resolved = NULL; /* target list after resolvedeps */ /* Build up list by repeatedly resolving each transaction package */ /* Resolve targets dependencies */ EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "resolving target's dependencies\n"); /* build remove list for resolvedeps */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; for(j = spkg->removes; j; j = j->next) { remove = alpm_list_add(remove, j->data); } } /* Compute the fake local database for resolvedeps (partial fix for the * phonon/qt issue) */ alpm_list_t *localpkgs = alpm_list_diff(_alpm_db_get_pkgcache(handle->db_local), trans->add, _alpm_pkg_cmp); /* Resolve packages in the transaction one at a time, in addition building up a list of packages which could not be resolved. */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(_alpm_resolvedeps(handle, localpkgs, pkg, trans->add, &resolved, remove, data) == -1) { unresolvable = alpm_list_add(unresolvable, pkg); } /* Else, [resolved] now additionally contains [pkg] and all of its dependencies not already on the list */ } alpm_list_free(localpkgs); /* If there were unresolvable top-level packages, prompt the user to see if they'd like to ignore them rather than failing the sync */ if(unresolvable != NULL) { int remove_unresolvable = 0; QUESTION(trans, ALPM_TRANS_CONV_REMOVE_PKGS, unresolvable, NULL, NULL, &remove_unresolvable); if(remove_unresolvable) { /* User wants to remove the unresolvable packages from the transaction. The packages will be removed from the actual transaction when the transaction packages are replaced with a dependency-reordered list below */ handle->pm_errno = 0; /* pm_errno was set by resolvedeps */ if(data) { alpm_list_free_inner(*data, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(*data); *data = NULL; } } else { /* pm_errno is set by resolvedeps */ alpm_list_free(resolved); ret = -1; goto cleanup; } } /* Set DEPEND reason for pulled packages */ for(i = resolved; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(!_alpm_pkg_find(trans->add, pkg->name)) { pkg->reason = ALPM_PKG_REASON_DEPEND; } } /* Unresolvable packages will be removed from the target list, so we free the transaction specific fields */ alpm_list_free_inner(unresolvable, (alpm_list_fn_free)_alpm_pkg_free_trans); /* re-order w.r.t. dependencies */ alpm_list_free(trans->add); trans->add = _alpm_sortbydeps(handle, resolved, 0); alpm_list_free(resolved); EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_DONE, NULL, NULL); } if(!(trans->flags & ALPM_TRANS_FLAG_NOCONFLICTS)) { /* check for inter-conflicts and whatnot */ EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for conflicts\n"); /* 1. check for conflicts in the target list */ _alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs targets\n"); deps = _alpm_innerconflicts(handle, trans->add); for(i = deps; i; i = i->next) { alpm_conflict_t *conflict = i->data; alpm_pkg_t *rsync, *sync, *sync1, *sync2; /* have we already removed one of the conflicting targets? */ sync1 = _alpm_pkg_find(trans->add, conflict->package1); sync2 = _alpm_pkg_find(trans->add, conflict->package2); if(!sync1 || !sync2) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n", conflict->package1, conflict->package2); /* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */ alpm_depend_t *dep1 = _alpm_splitdep(conflict->package1); alpm_depend_t *dep2 = _alpm_splitdep(conflict->package2); if(_alpm_depcmp(sync1, dep2)) { rsync = sync2; sync = sync1; } else if(_alpm_depcmp(sync2, dep1)) { rsync = sync1; sync = sync2; } else { _alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n")); handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS; ret = -1; if(data) { alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict); if(newconflict) { *data = alpm_list_add(*data, newconflict); } } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); _alpm_dep_free(dep1); _alpm_dep_free(dep2); goto cleanup; } _alpm_dep_free(dep1); _alpm_dep_free(dep2); /* Prints warning */ _alpm_log(handle, ALPM_LOG_WARNING, _("removing '%s' from target list because it conflicts with '%s'\n"), rsync->name, sync->name); trans->add = alpm_list_remove(trans->add, rsync, _alpm_pkg_cmp, NULL); _alpm_pkg_free_trans(rsync); /* rsync is not transaction target anymore */ continue; } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); deps = NULL; /* 2. we check for target vs db conflicts (and resolve)*/ _alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs db and db vs targets\n"); deps = _alpm_outerconflicts(handle->db_local, trans->add); for(i = deps; i; i = i->next) { alpm_conflict_t *conflict = i->data; /* if conflict->package2 (the local package) is not elected for removal, we ask the user */ int found = 0; for(j = trans->add; j && !found; j = j->next) { alpm_pkg_t *spkg = j->data; if(_alpm_pkg_find(spkg->removes, conflict->package2)) { found = 1; } } if(found) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", conflict->package1, conflict->package2); alpm_pkg_t *sync = _alpm_pkg_find(trans->add, conflict->package1); alpm_pkg_t *local = _alpm_db_get_pkgfromcache(handle->db_local, conflict->package2); int doremove = 0; QUESTION(trans, ALPM_TRANS_CONV_CONFLICT_PKG, conflict->package1, conflict->package2, conflict->reason, &doremove); if(doremove) { /* append to the removes list */ _alpm_log(handle, ALPM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2); sync->removes = alpm_list_add(sync->removes, local); } else { /* abort */ _alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n")); handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS; ret = -1; if(data) { alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict); if(newconflict) { *data = alpm_list_add(*data, newconflict); } } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); goto cleanup; } } EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL); alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); alpm_list_free(deps); } /* Build trans->remove list */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; for(j = spkg->removes; j; j = j->next) { alpm_pkg_t *rpkg = j->data; if(!_alpm_pkg_find(trans->remove, rpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "adding '%s' to remove list\n", rpkg->name); trans->remove = alpm_list_add(trans->remove, _alpm_pkg_dup(rpkg)); } } } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { _alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n"); deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), trans->remove, trans->add, 1); if(deps) { handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS; ret = -1; if(data) { *data = deps; } else { alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(deps); } goto cleanup; } } for(i = trans->add; i; i = i->next) { /* update download size field */ alpm_pkg_t *spkg = i->data; if(compute_download_size(spkg) != 0) { ret = -1; goto cleanup; } } cleanup: alpm_list_free(unresolvable); alpm_list_free(remove); return ret; }
/** * pacman_list_diff: * @lhs: A #PacmanList. * @rhs: A #PacmanList. * @func: A #GCompareFunc function. * * Creates a new list from items in @lhs that have no equivalent in @rhs (as determined by @func). * * Returns: A #PacmanList. Free with pacman_list_free(). */ PacmanList *pacman_list_diff (const PacmanList *lhs, const PacmanList *rhs, GCompareFunc func) { return alpm_list_diff (lhs, rhs, (alpm_list_fn_cmp) func); }