Add interactive provider selection
If there are multiple providers in one db, pacman used to just stop at the first one (both during dependency resolution or for pacman -S 'provision' which uses the same code). This adds a new conversation callback so that the user can choose which provider to install. By default (user press enter or --noconfirm), the first provider is still chosen, so for example the behavior of sync402 and 403 is preserved. But at least the user now has the possibility to make the right choice in a manual run. If one of the provider is already installed, it is picked for reinstall/upgrade, so that provision 002/003 pactest now pass. $ pacman -S community/smtp-server :: There are 3 providers available for smtp-server: 1) courier-mta 2) esmtp 3) exim Which one do you want to install? Enter a number (default=1): Signed-off-by: Xavier Chantry <chantry.xavier@gmail.com>
This commit is contained in:
parent
ba97a22ce1
commit
4097c98c1e
7 changed files with 106 additions and 7 deletions
|
@ -383,6 +383,7 @@ typedef enum _pmtransconv_t {
|
||||||
PM_TRANS_CONV_CORRUPTED_PKG = (1 << 3),
|
PM_TRANS_CONV_CORRUPTED_PKG = (1 << 3),
|
||||||
PM_TRANS_CONV_LOCAL_NEWER = (1 << 4),
|
PM_TRANS_CONV_LOCAL_NEWER = (1 << 4),
|
||||||
PM_TRANS_CONV_REMOVE_PKGS = (1 << 5),
|
PM_TRANS_CONV_REMOVE_PKGS = (1 << 5),
|
||||||
|
PM_TRANS_CONV_SELECT_PROVIDER = (1 << 6),
|
||||||
} pmtransconv_t;
|
} pmtransconv_t;
|
||||||
|
|
||||||
/* Transaction Progress */
|
/* Transaction Progress */
|
||||||
|
|
|
@ -511,6 +511,10 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,
|
||||||
{
|
{
|
||||||
alpm_list_t *i, *j;
|
alpm_list_t *i, *j;
|
||||||
int ignored = 0;
|
int ignored = 0;
|
||||||
|
|
||||||
|
alpm_list_t *providers = NULL;
|
||||||
|
int count;
|
||||||
|
|
||||||
/* 1. literals */
|
/* 1. literals */
|
||||||
for(i = dbs; i; i = i->next) {
|
for(i = dbs; i; i = i->next) {
|
||||||
pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name);
|
pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name);
|
||||||
|
@ -550,12 +554,40 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_alpm_log(PM_LOG_WARNING, _("provider package was selected (%s provides %s)\n"),
|
_alpm_log(PM_LOG_DEBUG, "provider found (%s provides %s)\n",
|
||||||
pkg->name, dep->name);
|
pkg->name, dep->name);
|
||||||
|
providers = alpm_list_add(providers, pkg);
|
||||||
|
/* keep looking for other providers in the all dbs */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first check if one provider is already installed locally */
|
||||||
|
for(i = providers; i; i = i->next) {
|
||||||
|
pmpkg_t *pkg = i->data;
|
||||||
|
if (_alpm_pkg_find(_alpm_db_get_pkgcache(handle->db_local), pkg->name)) {
|
||||||
|
alpm_list_free(providers);
|
||||||
return(pkg);
|
return(pkg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
count = alpm_list_count(providers);
|
||||||
|
if (count >= 1) {
|
||||||
|
/* default to first provider if there is no QUESTION callback */
|
||||||
|
int index = 0;
|
||||||
|
if(count > 1) {
|
||||||
|
/* if there is more than one provider, we ask the user */
|
||||||
|
QUESTION(handle->trans, PM_TRANS_CONV_SELECT_PROVIDER,
|
||||||
|
providers, dep, NULL, &index);
|
||||||
}
|
}
|
||||||
|
if(index >= 0 && index < count) {
|
||||||
|
pmpkg_t *pkg = alpm_list_getdata(alpm_list_nth(providers, index));
|
||||||
|
alpm_list_free(providers);
|
||||||
|
return(pkg);
|
||||||
|
}
|
||||||
|
alpm_list_free(providers);
|
||||||
|
providers = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(ignored) { /* resolvedeps will override these */
|
if(ignored) { /* resolvedeps will override these */
|
||||||
pm_errno = PM_ERR_PKG_IGNORED;
|
pm_errno = PM_ERR_PKG_IGNORED;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -302,6 +302,19 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,
|
||||||
alpm_list_free(namelist);
|
alpm_list_free(namelist);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PM_TRANS_CONV_SELECT_PROVIDER:
|
||||||
|
{
|
||||||
|
alpm_list_t *providers = (alpm_list_t *)data1;
|
||||||
|
int count = alpm_list_count(providers);
|
||||||
|
char *depstring = alpm_dep_compute_string((pmdepend_t *)data2);
|
||||||
|
printf(_(":: There are %d providers available for %s:\n"), count,
|
||||||
|
depstring);
|
||||||
|
free(depstring);
|
||||||
|
select_display(providers);
|
||||||
|
printf("\n");
|
||||||
|
*response = select_question(count);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PM_TRANS_CONV_LOCAL_NEWER:
|
case PM_TRANS_CONV_LOCAL_NEWER:
|
||||||
if(!config->op_s_downloadonly) {
|
if(!config->op_s_downloadonly) {
|
||||||
*response = yesno(_(":: %s-%s: local version is newer. Upgrade anyway?"),
|
*response = yesno(_(":: %s-%s: local version is newer. Upgrade anyway?"),
|
||||||
|
|
|
@ -677,6 +677,61 @@ void display_optdepends(pmpkg_t *pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void select_display(const alpm_list_t *pkglist)
|
||||||
|
{
|
||||||
|
const alpm_list_t *i;
|
||||||
|
int nth = 1;
|
||||||
|
alpm_list_t *list = NULL;
|
||||||
|
char *string = NULL;
|
||||||
|
|
||||||
|
for (i = pkglist; i; i = i->next) {
|
||||||
|
string = NULL;
|
||||||
|
pm_asprintf(&string, "%d) %s", nth, alpm_pkg_get_name(i->data));
|
||||||
|
list = alpm_list_add(list, string);
|
||||||
|
nth++;
|
||||||
|
}
|
||||||
|
list_display(" ", list);
|
||||||
|
FREELIST(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int select_question(int count)
|
||||||
|
{
|
||||||
|
char response[32];
|
||||||
|
FILE *stream;
|
||||||
|
int preset = 1;
|
||||||
|
|
||||||
|
if(config->noconfirm) {
|
||||||
|
stream = stdout;
|
||||||
|
} else {
|
||||||
|
/* Use stderr so questions are always displayed when redirecting output */
|
||||||
|
stream = stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stream, _("Enter a number (default=%d)"), preset);
|
||||||
|
fprintf(stream, ": ");
|
||||||
|
|
||||||
|
if(config->noconfirm) {
|
||||||
|
fprintf(stream, "\n");
|
||||||
|
return(preset-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fgets(response, sizeof(response), stdin)) {
|
||||||
|
strtrim(response);
|
||||||
|
if(strlen(response) > 0) {
|
||||||
|
char *endptr = NULL;
|
||||||
|
int n = strtol(response, &endptr, 10);
|
||||||
|
if(*endptr == '\0' && n >= 1 && n <= count) {
|
||||||
|
return(n-1);
|
||||||
|
} else {
|
||||||
|
fprintf(stream, _("Invalid number: %s\n"), response);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(preset-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* presents a prompt and gets a Y/N answer */
|
/* presents a prompt and gets a Y/N answer */
|
||||||
static int question(short preset, char *fmt, va_list args)
|
static int question(short preset, char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,6 +59,8 @@ int str_cmp(const void *s1, const void *s2);
|
||||||
void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg);
|
void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg);
|
||||||
void display_optdepends(pmpkg_t *pkg);
|
void display_optdepends(pmpkg_t *pkg);
|
||||||
void print_packages(const alpm_list_t *packages);
|
void print_packages(const alpm_list_t *packages);
|
||||||
|
void select_display(const alpm_list_t *pkglist);
|
||||||
|
int select_question(int count);
|
||||||
int yesno(char *fmt, ...);
|
int yesno(char *fmt, ...);
|
||||||
int noyes(char *fmt, ...);
|
int noyes(char *fmt, ...);
|
||||||
int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3)));
|
int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3)));
|
||||||
|
|
|
@ -18,5 +18,3 @@ self.addrule("PACMAN_RETCODE=0")
|
||||||
self.addrule("!PKG_EXIST=pkg1")
|
self.addrule("!PKG_EXIST=pkg1")
|
||||||
self.addrule("PKG_EXIST=pkg2")
|
self.addrule("PKG_EXIST=pkg2")
|
||||||
self.addrule("PKG_VERSION=pkg2|1.0-2")
|
self.addrule("PKG_VERSION=pkg2|1.0-2")
|
||||||
|
|
||||||
self.expectfailure = True
|
|
||||||
|
|
|
@ -19,5 +19,3 @@ self.addrule("PACMAN_RETCODE=0")
|
||||||
self.addrule("!PKG_EXIST=pkg1")
|
self.addrule("!PKG_EXIST=pkg1")
|
||||||
self.addrule("PKG_EXIST=pkg2")
|
self.addrule("PKG_EXIST=pkg2")
|
||||||
self.addrule("PKG_VERSION=pkg2|1.0-2")
|
self.addrule("PKG_VERSION=pkg2|1.0-2")
|
||||||
|
|
||||||
self.expectfailure = True
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue