/** Find a package satisfying a specified dependency. * The dependency can include versions with depmod operators. * @param pkgs an alpm_list_t* of alpm_pkg_t where the satisfier will be searched * @param depstring package or provision name, versioned or not * @return a alpm_pkg_t* satisfying depstring */ alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring) { alpm_depend_t *dep = _alpm_splitdep(depstring); if(!dep) { return NULL; } alpm_pkg_t *pkg = find_dep_satisfier(pkgs, dep); _alpm_dep_free(dep); return pkg; }
/** Checks dependencies and returns missing ones in a list. * Dependencies can include versions with depmod operators. * @param handle the context handle * @param pkglist the list of local packages * @param remove an alpm_list_t* of packages to be removed * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade) * @param reversedeps handles the backward dependencies * @return an alpm_list_t* of alpm_depmissing_t pointers. */ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist, alpm_list_t *rem, alpm_list_t *upgrade, int reversedeps) { alpm_list_t *i, *j; alpm_list_t *dblist = NULL, *modified = NULL; alpm_list_t *baddeps = NULL; int nodepversion; CHECK_HANDLE(handle, return NULL); for(i = pkglist; i; i = i->next) { alpm_pkg_t *pkg = i->data; if(alpm_pkg_find(rem, pkg->name) || alpm_pkg_find(upgrade, pkg->name)) { modified = alpm_list_add(modified, pkg); } else { dblist = alpm_list_add(dblist, pkg); } } nodepversion = no_dep_version(handle); /* look for unsatisfied dependencies of the upgrade list */ for(i = upgrade; i; i = i->next) { alpm_pkg_t *tp = i->data; _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: package %s-%s\n", tp->name, tp->version); for(j = alpm_pkg_get_depends(tp); j; j = j->next) { alpm_depend_t *depend = j->data; depend = filtered_depend(depend, nodepversion); /* 1. we check the upgrade list */ /* 2. we check database for untouched satisfying packages */ if(!find_dep_satisfier(upgrade, depend) && !find_dep_satisfier(dblist, depend)) { /* Unsatisfied dependency in the upgrade list */ alpm_depmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", missdepstring, tp->name); free(missdepstring); miss = depmiss_new(tp->name, depend, NULL); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); } } if(reversedeps) { /* reversedeps handles the backwards dependencies, ie, * the packages listed in the requiredby field. */ for(i = dblist; i; i = i->next) { alpm_pkg_t *lp = i->data; for(j = alpm_pkg_get_depends(lp); j; j = j->next) { alpm_depend_t *depend = j->data; depend = filtered_depend(depend, nodepversion); alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend); /* we won't break this depend, if it is already broken, we ignore it */ /* 1. check upgrade list for satisfiers */ /* 2. check dblist for satisfiers */ if(causingpkg && !find_dep_satisfier(upgrade, depend) && !find_dep_satisfier(dblist, depend)) { alpm_depmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", missdepstring, lp->name); free(missdepstring); miss = depmiss_new(lp->name, depend, causingpkg->name); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); } } } alpm_list_free(modified); alpm_list_free(dblist); return baddeps; }
/** * Computes resolvable dependencies for a given package and adds that package * and those resolvable dependencies to a list. * * @param handle the context handle * @param localpkgs is the list of local packages * @param pkg is the package to resolve * @param packages is a pointer to a list of packages which will be * searched first for any dependency packages needed to complete the * resolve, and to which will be added any [pkg] and all of its * dependencies not already on the list * @param remove is the set of packages which will be removed in this * transaction * @param data returns the dependency which could not be satisfied in the * event of an error * @return 0 on success, with [pkg] and all of its dependencies not already on * the [*packages] list added to that list, or -1 on failure due to an * unresolvable dependency, in which case the [*packages] list will be * unmodified by this function */ int _alpm_resolvedeps(pmhandle_t *handle, alpm_list_t *localpkgs, pmpkg_t *pkg, alpm_list_t *preferred, alpm_list_t **packages, alpm_list_t *remove, alpm_list_t **data) { int ret = 0; alpm_list_t *i, *j; alpm_list_t *targ; alpm_list_t *deps = NULL; alpm_list_t *packages_copy; if(_alpm_pkg_find(*packages, pkg->name) != NULL) { return 0; } /* Create a copy of the packages list, so that it can be restored on error */ packages_copy = alpm_list_copy(*packages); /* [pkg] has not already been resolved into the packages list, so put it on that list */ *packages = alpm_list_add(*packages, pkg); _alpm_log(handle, PM_LOG_DEBUG, "started resolving dependencies\n"); for(i = alpm_list_last(*packages); i; i = i->next) { pmpkg_t *tpkg = i->data; targ = alpm_list_add(NULL, tpkg); deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0); alpm_list_free(targ); for(j = deps; j; j = j->next) { pmdepmissing_t *miss = j->data; pmdepend_t *missdep = miss->depend; /* check if one of the packages in the [*packages] list already satisfies * this dependency */ if(find_dep_satisfier(*packages, missdep)) { _alpm_depmiss_free(miss); continue; } /* check if one of the packages in the [preferred] list already satisfies * this dependency */ pmpkg_t *spkg = find_dep_satisfier(preferred, missdep); if(!spkg) { /* find a satisfier package in the given repositories */ spkg = resolvedep(handle, missdep, handle->dbs_sync, *packages, 0); } if(!spkg) { handle->pm_errno = PM_ERR_UNSATISFIED_DEPS; char *missdepstring = alpm_dep_compute_string(missdep); _alpm_log(handle, PM_LOG_WARNING, _("cannot resolve \"%s\", a dependency of \"%s\"\n"), missdepstring, tpkg->name); free(missdepstring); if(data) { *data = alpm_list_add(*data, miss); } ret = -1; } else { _alpm_log(handle, PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n", alpm_pkg_get_name(spkg), alpm_pkg_get_name(tpkg)); *packages = alpm_list_add(*packages, spkg); _alpm_depmiss_free(miss); } } alpm_list_free(deps); } if(ret != 0) { alpm_list_free(*packages); *packages = packages_copy; } else { alpm_list_free(packages_copy); } _alpm_log(handle, PM_LOG_DEBUG, "finished resolving dependencies\n"); return ret; }