[pacman-dev] [PATCH 1/4] Internal code reorganization in preparation for changes to package resolution.
This change reorganizes the internal code so that packages are resolved one at a time instead of all at once from a list. This will allow a future checkin to prompt the user to see if they'd rather remove unresolvable packages from the tranasaction and continue, or fail the transaction. This change does not affect the actual behavior of libalpm and all tests pass without changes. Signed-off-by: Bryan Ischo <bryan@ischo.com> --- lib/libalpm/deps.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------- lib/libalpm/deps.h | 5 ++- lib/libalpm/sync.c | 52 +++++++++++++++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 940f12c..a5b57ad 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 - * - * @param remove contains packages elected for removal +/* Computes resolvable dependencies for a given package and adds that package + * and those resolvable dependencies to a list. + * + * @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 *working; ALPM_LOG_FUNC; @@ -564,8 +580,21 @@ 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) { + /* It's already on the list, meaning it's already been resolved and + it and all of its dependencies have already been added */ + return(0); + } + + /* [pkg] has not already been resolved into the packages list, so put it + * on that list */ + *packages = alpm_list_add(*packages, pkg); + /* And keep track of the head of the newly-added elements, so that they + can be quickly cut from the list on error */ + working = alpm_list_last(*packages); + _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n"); - for(i = list; i; i = i->next) { + for(i = working; 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 +602,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,13 +621,26 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, *data = alpm_list_add(*data, missd); } } + /* Remove all packages that were added to [*packages], so that + * we return from error cleanly without having affected the + * [*packages] list. Detach the tail of the list beginning at + * [working] from the packages list and free it. */ + if (working == *packages) { + *packages = NULL; + } + else { + (*packages)->prev = working->prev; + (*packages)->prev->next = NULL; + working->prev = NULL; + } + alpm_list_free(working); 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); diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 2f3c450..9dca91d 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -48,8 +48,9 @@ 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 b458874..5daadbd 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,14 @@ 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) { + /* Simply build up [list] from all of the transaction packages */ + 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 +432,43 @@ 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) { + /* Failed to resolve a dependency of [pkg]. It goes on the + unresolvable list. [list] was not touched, so no + unnecessary dependency packages were added to it. */ + 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. In a future checkin, the user will be asked if they'd + like to drop the unresolvable packages intead. */ + 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 +656,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); }
On Fri, Jan 16, 2009 at 8:13 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
This change reorganizes the internal code so that packages are resolved one at a time instead of all at once from a list. This will allow a future checkin to prompt the user to see if they'd rather remove unresolvable packages from the tranasaction and continue, or fail the transaction. This change does not affect the actual behavior of libalpm and all tests pass without changes.
Please wrap your commit message at 76 characters so it doesn't make the git-log console output go crazy.
Signed-off-by: Bryan Ischo <bryan@ischo.com> --- lib/libalpm/deps.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------- lib/libalpm/deps.h | 5 ++- lib/libalpm/sync.c | 52 +++++++++++++++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 24 deletions(-)
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 940f12c..a5b57ad 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 - * - * @param remove contains packages elected for removal +/* Computes resolvable dependencies for a given package and adds that package + * and those resolvable dependencies to a list. + * + * @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)
No need to use two lines for what will fit on one line.
{ alpm_list_t *i, *j; alpm_list_t *targ; alpm_list_t *deps = NULL; + alpm_list_t *working;
ALPM_LOG_FUNC;
@@ -564,8 +580,21 @@ 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) { + /* It's already on the list, meaning it's already been resolved and + it and all of its dependencies have already been added */ Drop this comment- its pretty obvious what the conditional is checking.
+ return(0); + } + + /* [pkg] has not already been resolved into the packages list, so put it + * on that list */ + *packages = alpm_list_add(*packages, pkg); + /* And keep track of the head of the newly-added elements, so that they + can be quickly cut from the list on error */ + working = alpm_list_last(*packages); + _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n"); - for(i = list; i; i = i->next) { + for(i = working; 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 +602,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,13 +621,26 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, *data = alpm_list_add(*data, missd); } } + /* Remove all packages that were added to [*packages], so that + * we return from error cleanly without having affected the + * [*packages] list. Detach the tail of the list beginning at + * [working] from the packages list and free it. */ + if (working == *packages) { + *packages = NULL; + } + else { + (*packages)->prev = working->prev; + (*packages)->prev->next = NULL; + working->prev = NULL; + } + alpm_list_free(working); Hmm, I'm not a fan of this manual manipulation- the data structures are there for a reason, so we aren't playing with pointers. The problem here is edge cases are likely to break- I'm not sure if you know, but we ensured alpm_list_last() is an O(1) operation for example by linking first->prev to the last item (the inverse is not true).
You might be better off keeping two independent lists and then finding a way to join them when we are past the point of no return.
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); diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 2f3c450..9dca91d 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -48,8 +48,9 @@ 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);
Coalesce the previous two lines. If you do that I'll stop pulling stupid words like 'coalesce' out of my vocab too. :)
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 b458874..5daadbd 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,14 @@ 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) { + /* Simply build up [list] from all of the transaction packages */ Unnecessary comment.
+ 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 +432,43 @@ 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) { + /* Failed to resolve a dependency of [pkg]. It goes on the + unresolvable list. [list] was not touched, so no + unnecessary dependency packages were added to it. */ I know it sounds weird to hate on comments, but it takes me a lot longer to get through the comment than just reading the code and seeing what it says. Shorten or kill this one.
+ 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. In a future checkin, the user will be asked if they'd + like to drop the unresolvable packages intead. */ Don't tie in future checkins, we all know its coming. Just drop the comment.
+ 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 +656,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); }
I know I commented a lot, but overall this patch looks fine to me. If you make the adjustments I've pointed out I'll merge this. -Dan
Dan McGee wrote:
On Fri, Jan 16, 2009 at 8:13 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
This change reorganizes the internal code so that packages are resolved one at a time instead of all at once from a list. This will allow a future checkin to prompt the user to see if they'd rather remove unresolvable packages from the tranasaction and continue, or fail the transaction. This change does not affect the actual behavior of libalpm and all tests pass without changes.
Please wrap your commit message at 76 characters so it doesn't make the git-log console output go crazy.
Heh. Sorry about that. I am usually Mr. Anal 80 column man. Since the pacman source doesn't obey 80 column line limits I assumed that nobody did for anything ... but I guess that commit messages need to be wrapped. Believe me, I'm OK with that - I'd like to re-wrap all of the source too but ... I'll resist the urge :) Thanks, Bryan
On Fri, Jan 16, 2009 at 9:04 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
Dan McGee wrote:
On Fri, Jan 16, 2009 at 8:13 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
This change reorganizes the internal code so that packages are resolved one at a time instead of all at once from a list. This will allow a future checkin to prompt the user to see if they'd rather remove unresolvable packages from the tranasaction and continue, or fail the transaction. This change does not affect the actual behavior of libalpm and all tests pass without changes.
Please wrap your commit message at 76 characters so it doesn't make the git-log console output go crazy.
Heh. Sorry about that. I am usually Mr. Anal 80 column man. Since the pacman source doesn't obey 80 column line limits I assumed that nobody did for anything ... but I guess that commit messages need to be wrapped. Believe me, I'm OK with that - I'd like to re-wrap all of the source too but ... I'll resist the urge :)
I believe the pacman source does, but we cheat a little bit- note the modelines in each file that change our tabstops to 4 characters rather than 8. -Dan
Dan McGee wrote:
On Fri, Jan 16, 2009 at 9:04 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
Dan McGee wrote:
Please wrap your commit message at 76 characters so it doesn't make the git-log console output go crazy.
Heh. Sorry about that. I am usually Mr. Anal 80 column man. Since the pacman source doesn't obey 80 column line limits I assumed that nobody did for anything ... but I guess that commit messages need to be wrapped. Believe me, I'm OK with that - I'd like to re-wrap all of the source too but ... I'll resist the urge :)
I believe the pacman source does, but we cheat a little bit- note the modelines in each file that change our tabstops to 4 characters rather than 8.
Hm, well the HACKING file that lays out coding conventions doesn't mention line length. And I only really worked heavily in lib/libalpm/deps.c and lib/libalpm/sync.c, and those files have many lines that exceed 80 columns. But certainly other files I looked at also had lines exceeding 80 columns. It looks like maybe at one time the files were 80-column clean but that further changes have violated that rule. I do have my tab stops set at 4 spaces so I think you should see the same thing. Knowing that there is supposed to be an 80 column rule, I'll be sure to obey that in the future. Thanks, Bryan
Oh ... I was just looking through some old email and I realized that there were more comments in your response than I had initially seen. I had never responded to those and didn't realize that you were waiting for my response. Sorry about that, my responses are below inline. Dan McGee wrote:
On Fri, Jan 16, 2009 at 8:13 PM, Bryan Ischo <bji-keyword-pacman.3644cb@www.ischo.com> wrote:
This change reorganizes the internal code so that packages are resolved one at a time instead of all at once from a list. This will allow a future checkin to prompt the user to see if they'd rather remove unresolvable packages from the tranasaction and continue, or fail the transaction. This change does not affect the actual behavior of libalpm and all tests pass without changes.
Please wrap your commit message at 76 characters so it doesn't make the git-log console output go crazy.
Will do.
-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)
No need to use two lines for what will fit on one line.
Using tabs of width 4, the above is required to prevent breaking the 80 column rule. If you are using smaller tabs, you might be able to fit more on a line. Using tabs instead of spaces for indentation is the root cause of problems like this, but since the pacman coding conventions require tabs for indentation, there isn't a good way around this problem. That being said, since I just want this patch to get accepted, I'm happy to make the indentation look however you want, even if it breaks the 80 column rule. But I don't know exactly what you want - can you please send me a patch on my patch or something that re-jiggers these lines how you want them to be? In the short term, I'll try to guess what you wanted and hopefully I'll get it right.
+ if(_alpm_pkg_find(*packages, pkg->name) != NULL) { + /* It's already on the list, meaning it's already been resolved and + it and all of its dependencies have already been added */
Drop this comment- its pretty obvious what the conditional is checking.
Obvious to you, maybe. I think the comment is helpful, but I think we have a philosophical difference about comments as becomes apparent from your later comments. I can't see how comments could possibly be harmful; just because something is obvious to you on your read through the code doesn't mean it's obvious to someone else. But like I said, I just want my patch to be accepted, so I'll remove the comment.
+ /* Remove all packages that were added to [*packages], so that + * we return from error cleanly without having affected the + * [*packages] list. Detach the tail of the list beginning at + * [working] from the packages list and free it. */ + if (working == *packages) { + *packages = NULL; + } + else { + (*packages)->prev = working->prev; + (*packages)->prev->next = NULL; + working->prev = NULL; + } + alpm_list_free(working);
Hmm, I'm not a fan of this manual manipulation- the data structures are there for a reason, so we aren't playing with pointers. The problem here is edge cases are likely to break- I'm not sure if you know, but we ensured alpm_list_last() is an O(1) operation for example by linking first->prev to the last item (the inverse is not true).
Yes, I figured out how the linked list code worked via inspection. Having a back pointer from the head to the tail but not a forward pointer from the tail to the head is pretty weird, but I guess it works here. I tried adding a "alpm_list_cut" function to cut the ending segment of a linked list which would have worked here, but it seemed like a pretty arbitrary function to be adding to the linked list code, so I backed it out and just did some manual manipulation here.
You might be better off keeping two independent lists and then finding a way to join them when we are past the point of no return.
Yes, I tried that too, but it was alot more code to manage two lists than it was to simply 'undo' modifications to the list by removing them. Probably the simplest thing to do would be to copy the input list, and then either restore that copy before returning an error, or delete the copy before returning success. It is not the most runtime efficient, but it is simple and it re-uses existing linked list functions. I hope that is sufficient, because I really don't want to complicate the code needlessly by keeping the list segmented in two pieces until a join at the end.
diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 2f3c450..9dca91d 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -48,8 +48,9 @@ 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);
Coalesce the previous two lines. If you do that I'll stop pulling stupid words like 'coalesce' out of my vocab too. :)
Once again, I cannot without breaking the 80 column rule (with width-4 tab stops). Of course, there's no such thing as "80 columns" when you're using tabs for indentation so I guess it's kind of arbitrary where lines are split. If I set my own tab stops to 2 spaces and then indent for 80 columns will this break lines up the way you'd like to see them?
+ if(trans->flags & PM_TRANS_FLAG_NODEPS) { + /* Simply build up [list] from all of the transaction packages */
Unnecessary comment.
Once again, philosophical differences. But I will do as you ask.
+ if(_alpm_resolvedeps(db_local, dbs_sync, pkg, &list, remove, data) == -1) { + /* Failed to resolve a dependency of [pkg]. It goes on the + unresolvable list. [list] was not touched, so no + unnecessary dependency packages were added to it. */
I know it sounds weird to hate on comments, but it takes me a lot longer to get through the comment than just reading the code and seeing what it says. Shorten or kill this one.
As before, OK.
+ + /* If there were unresolvable top-level packages, fail the + transaction. In a future checkin, the user will be asked if they'd + like to drop the unresolvable packages intead. */
Don't tie in future checkins, we all know its coming. Just drop the comment.
Well I really disagree here. And I don't understand why it's important to change this because this comment is undone in the next patch in the patch set. But as with everything else, I'll change it just to get my patch accepted.
I know I commented a lot, but overall this patch looks fine to me. If you make the adjustments I've pointed out I'll merge this.
I will make the changes you requested. I don't know exactly what I need to do to 'fix' the two cases where I broke up a function prototype/signature because it seems dependent on how you've set your tab stops. But I will do my best. Thanks, Bryan
participants (2)
-
Bryan Ischo
-
Dan McGee