summaryrefslogtreecommitdiff
path: root/lib/libalpm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm')
-rw-r--r--lib/libalpm/deps.c50
-rw-r--r--lib/libalpm/deps.h4
-rw-r--r--lib/libalpm/sync.c47
3 files changed, 78 insertions, 23 deletions
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index 940f12ce..41d2a83f 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -546,17 +546,33 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *exclud
return(NULL);
}
-/* populates list with packages that need to be installed to satisfy all
- * dependencies of packages in list
+/* Computes resolvable dependencies for a given package and adds that package
+ * and those resolvable dependencies to a list.
*
- * @param remove contains packages elected for removal
+ * @param local is the local database
+ * @param dbs_sync are the sync databases
+ * @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(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list,
- alpm_list_t *remove, alpm_list_t **data)
+int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *pkg,
+ alpm_list_t **packages, alpm_list_t *remove,
+ alpm_list_t **data)
{
alpm_list_t *i, *j;
alpm_list_t *targ;
alpm_list_t *deps = NULL;
+ alpm_list_t *packages_copy;
ALPM_LOG_FUNC;
@@ -564,8 +580,19 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list,
return(-1);
}
+ 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(PM_LOG_DEBUG, "started resolving dependencies\n");
- for(i = list; i; i = i->next) {
+ for(i = alpm_list_last(*packages); i; i = i->next) {
pmpkg_t *tpkg = i->data;
targ = alpm_list_add(NULL, tpkg);
deps = alpm_checkdeps(_alpm_db_get_pkgcache(local), 0, remove, targ);
@@ -573,12 +600,12 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list,
for(j = deps; j; j = j->next) {
pmdepmissing_t *miss = j->data;
pmdepend_t *missdep = alpm_miss_get_dep(miss);
- /* check if one of the packages in list already satisfies this dependency */
- if(_alpm_find_dep_satisfier(list, missdep)) {
+ /* check if one of the packages in the [*packages] list already satisfies this dependency */
+ if(_alpm_find_dep_satisfier(*packages, missdep)) {
continue;
}
/* find a satisfier package in the given repositories */
- pmpkg_t *spkg = _alpm_resolvedep(missdep, dbs_sync, list, tpkg);
+ pmpkg_t *spkg = _alpm_resolvedep(missdep, dbs_sync, *packages, tpkg);
if(!spkg) {
pm_errno = PM_ERR_UNSATISFIED_DEPS;
char *missdepstring = alpm_dep_compute_string(missdep);
@@ -592,18 +619,21 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list,
*data = alpm_list_add(*data, missd);
}
}
+ alpm_list_free(*packages);
+ *packages = packages_copy;
alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
alpm_list_free(deps);
return(-1);
} else {
_alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n",
alpm_pkg_get_name(spkg), alpm_pkg_get_name(tpkg));
- list = alpm_list_add(list, spkg);
+ *packages = alpm_list_add(*packages, spkg);
}
}
alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
alpm_list_free(deps);
}
+ alpm_list_free(packages_copy);
_alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
return(0);
}
diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h
index 2f3c4502..07270957 100644
--- a/lib/libalpm/deps.h
+++ b/lib/libalpm/deps.h
@@ -48,8 +48,8 @@ void _alpm_depmiss_free(pmdepmissing_t *miss);
alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse);
void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit);
pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *excluding, pmpkg_t *tpkg);
-int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list,
- alpm_list_t *remove, alpm_list_t **data);
+int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *pkg,
+ alpm_list_t **packages, alpm_list_t *remove, alpm_list_t **data);
int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2);
pmdepend_t *_alpm_splitdep(const char *depstring);
pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep);
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index b458874d..5e5ca92e 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -399,6 +399,7 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
{
alpm_list_t *deps = NULL;
alpm_list_t *list = NULL, *remove = NULL; /* allow checkdeps usage with trans->packages */
+ alpm_list_t *unresolvable = NULL;
alpm_list_t *i, *j;
int ret = 0;
@@ -411,15 +412,13 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
*data = NULL;
}
- for(i = trans->packages; i; i = i->next) {
- pmsyncpkg_t *sync = i->data;
- list = alpm_list_add(list, sync->pkg);
- }
-
- if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
- /* store a pointer to the last original target so we can tell what was
- * pulled by resolvedeps */
- alpm_list_t *pulled = alpm_list_last(list);
+ if(trans->flags & PM_TRANS_FLAG_NODEPS) {
+ for(i = trans->packages; i; i = i->next) {
+ pmsyncpkg_t *sync = i->data;
+ list = alpm_list_add(list, sync->pkg);
+ }
+ } else {
+ /* Build up list by repeatedly resolving each transaction package */
/* Resolve targets dependencies */
EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL);
_alpm_log(PM_LOG_DEBUG, "resolving target's dependencies\n");
@@ -432,14 +431,39 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
}
}
- if(_alpm_resolvedeps(db_local, dbs_sync, list, remove, data) == -1) {
+ /* Resolve packages in the transaction one at a time, in addtion
+ building up a list of packages which could not be resolved. */
+ for(i = trans->packages; i; i = i->next) {
+ pmpkg_t *pkg = ((pmsyncpkg_t *) i->data)->pkg;
+ if(_alpm_resolvedeps(db_local, dbs_sync, pkg, &list, remove, data) == -1) {
+ unresolvable = alpm_list_add(unresolvable, pkg);
+ }
+ /* Else, [list] now additionally contains [pkg] and all of its
+ dependencies not already on the list */
+ }
+
+ /* If there were unresolvable top-level packages, fail the
+ transaction. */
+ if(unresolvable != NULL) {
/* pm_errno is set by resolvedeps */
ret = -1;
goto cleanup;
}
- for(i = pulled->next; i; i = i->next) {
+ /* Add all packages which were "pulled" (i.e. weren't already in the
+ transaction) to the transaction in pmsyncpkg_t structures */
+ for(i = list; i; i = i->next) {
pmpkg_t *spkg = i->data;
+ for(j = trans->packages; j; j = j->next) {
+ if(_alpm_pkg_cmp(spkg, ((pmsyncpkg_t *) j->data)->pkg) == 0) {
+ spkg = NULL;
+ break;
+ }
+ }
+ if (spkg == NULL) {
+ continue;
+ }
+
pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_DEPEND, spkg, NULL);
if(sync == NULL) {
ret = -1;
@@ -627,6 +651,7 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
cleanup:
alpm_list_free(list);
alpm_list_free(remove);
+ alpm_list_free(unresolvable);
return(ret);
}