Hello, I'm all in for this, thanks Sebastian. This would allow to remove a _HUGE_ quantity of unneeded callbacks in alpm, and from my point of view, it is really great (especially for Shaman/Aqpm). For what it's worth, I'd like to add my vote here and I really hope this patch will be in trunk soon, so that I can switch Shaman's frontend to this new system.
Dario In data venerdì 20 febbraio 2009 08:31:07, Sebastian Nowicki ha scritto: : > This allows a frontend to define its own download algorithm so that the > libfetch dependency can be omitted without using an external process. The > callback will be used if it is defined, otherwise the internal method > (libfetch) is used, if available. > > The external download method was moved to pacman and is set as the fetch > callback, if the command is defined in the configuration file. As a result, > alpm_option_get_xfercommand() and alpm_option_set_xfercommand() have been > removed. > > Signed-off-by: Sebastian Nowicki <[email protected]> > --- > lib/libalpm/alpm.h | 17 +++++++- > lib/libalpm/dload.c | 101 > +------------------------------------------------ lib/libalpm/handle.c | > 33 +++++++++------- > lib/libalpm/handle.h | 2 +- > src/pacman/conf.h | 6 +++ > src/pacman/pacman.c | 96 > +++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 137 > insertions(+), 118 deletions(-) > > diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h > index 7b7ca4e..f444e93 100644 > --- a/lib/libalpm/alpm.h > +++ b/lib/libalpm/alpm.h > @@ -83,6 +83,17 @@ int alpm_logaction(char *fmt, ...); > typedef void (*alpm_cb_download)(const char *filename, > off_t xfered, off_t total); > typedef void (*alpm_cb_totaldl)(off_t total); > +/** A callback for downloading files > + * @param url the URL of the file to be downloaded > + * @param localpath the directory to which the file should be downloaded > + * @param mtimeold the modification time of the file previously downloaded > + * @param mtimenew the modification time of the newly downloaded file. > + * This should be set by the callback. > + * @return 0 on success, 1 if the modification times are identical, -1 on > + * error. > + */ > +typedef int (*alpm_cb_fetch)(const char *url, const char *localpath, > + time_t mtimeold, time_t *mtimenew); > > /* > * Options > @@ -94,6 +105,9 @@ void alpm_option_set_logcb(alpm_cb_log cb); > alpm_cb_download alpm_option_get_dlcb(); > void alpm_option_set_dlcb(alpm_cb_download cb); > > +alpm_cb_fetch alpm_option_get_fetchcb(); > +void alpm_option_set_fetchcb(alpm_cb_fetch cb); > + > alpm_cb_totaldl alpm_option_get_totaldlcb(); > void alpm_option_set_totaldlcb(alpm_cb_totaldl cb); > > @@ -137,9 +151,6 @@ void alpm_option_add_ignoregrp(const char *grp); > void alpm_option_set_ignoregrps(alpm_list_t *ignoregrps); > int alpm_option_remove_ignoregrp(const char *grp); > > -const char *alpm_option_get_xfercommand(); > -void alpm_option_set_xfercommand(const char *cmd); > - > unsigned short alpm_option_get_nopassiveftp(); > void alpm_option_set_nopassiveftp(unsigned short nopasv); > void alpm_option_set_usedelta(unsigned short usedelta); > diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c > index 5b0a691..bc36706 100644 > --- a/lib/libalpm/dload.c > +++ b/lib/libalpm/dload.c > @@ -262,111 +262,16 @@ cleanup: > } > #endif > > -static int download_external(const char *url, const char *localpath, > - time_t mtimeold, time_t *mtimenew) { > - int ret = 0; > - int retval; > - int usepart = 0; > - char *ptr1, *ptr2; > - char origCmd[PATH_MAX]; > - char parsedCmd[PATH_MAX] = ""; > - char cwd[PATH_MAX]; > - char *destfile, *tempfile, *filename; > - > - if(!handle->xfercommand) { > - RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); > - } > - > - filename = get_filename(url); > - if(!filename) { > - RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); > - } > - destfile = get_destfile(localpath, filename); > - tempfile = get_tempfile(localpath, filename); > - > - /* replace all occurrences of %o with fn.part */ > - strncpy(origCmd, handle->xfercommand, sizeof(origCmd)); > - ptr1 = origCmd; > - while((ptr2 = strstr(ptr1, "%o"))) { > - usepart = 1; > - ptr2[0] = '\0'; > - strcat(parsedCmd, ptr1); > - strcat(parsedCmd, tempfile); > - ptr1 = ptr2 + 2; > - } > - strcat(parsedCmd, ptr1); > - /* replace all occurrences of %u with the download URL */ > - strncpy(origCmd, parsedCmd, sizeof(origCmd)); > - parsedCmd[0] = '\0'; > - ptr1 = origCmd; > - while((ptr2 = strstr(ptr1, "%u"))) { > - ptr2[0] = '\0'; > - strcat(parsedCmd, ptr1); > - strcat(parsedCmd, url); > - ptr1 = ptr2 + 2; > - } > - strcat(parsedCmd, ptr1); > - /* cwd to the download directory */ > - getcwd(cwd, PATH_MAX); > - if(chdir(localpath)) { > - _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), > localpath); > - pm_errno = PM_ERR_EXTERNAL_DOWNLOAD; > - ret = -1; > - goto cleanup; > - } > - /* execute the parsed command via /bin/sh -c */ > - _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd); > - retval = system(parsedCmd); > - > - if(retval == -1) { > - _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork > failed!\n")); > - pm_errno = PM_ERR_EXTERNAL_DOWNLOAD; > - ret = -1; > - } else if(retval != 0) { > - /* download failed */ > - _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero > status " > - "code (%d)\n", retval); > - ret = -1; > - } else { > - /* download was successful */ > - if(usepart) { > - rename(tempfile, destfile); > - } > - ret = 0; > - } > - > -cleanup: > - chdir(cwd); > - if(ret == -1) { > - /* hack to let an user the time to cancel a download */ > - sleep(2); > - } > - FREE(destfile); > - FREE(tempfile); > - > - return(ret); > -} > - > static int download(const char *url, const char *localpath, > time_t mtimeold, time_t *mtimenew) { > - int ret; > - > - /* We have a few things to take into account here. > - * 1. If we have both internal/external available, choose based on > - * whether xfercommand is populated. > - * 2. If we only have external available, we should first check > - * if a command was provided before we drop into download_external. > - */ > - if(handle->xfercommand == NULL) { > + if(handle->fetchcb == NULL) { > #if defined(INTERNAL_DOWNLOAD) > - ret = download_internal(url, localpath, mtimeold, mtimenew); > + handle->fetchcb = download_internal; > #else > RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); > #endif > - } else { > - ret = download_external(url, localpath, mtimeold, mtimenew); > } > - return(ret); > + return handle->fetchcb(url, localpath, mtimeold, mtimeold); > } > > /* > diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c > index 813f439..3566889 100644 > --- a/lib/libalpm/handle.c > +++ b/lib/libalpm/handle.c > @@ -105,6 +105,15 @@ alpm_cb_download SYMEXPORT alpm_option_get_dlcb() > return handle->dlcb; > } > > +alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb() > +{ > + if (handle == NULL) { > + pm_errno = PM_ERR_HANDLE_NULL; > + return NULL; > + } > + return handle->fetchcb; > +} > + > alpm_cb_totaldl SYMEXPORT alpm_option_get_totaldlcb() > { > if (handle == NULL) { > @@ -204,15 +213,6 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregrps() > return handle->ignoregrp; > } > > -const char SYMEXPORT *alpm_option_get_xfercommand() > -{ > - if (handle == NULL) { > - pm_errno = PM_ERR_HANDLE_NULL; > - return NULL; > - } > - return handle->xfercommand; > -} > - > unsigned short SYMEXPORT alpm_option_get_nopassiveftp() > { > if (handle == NULL) { > @@ -258,6 +258,15 @@ void SYMEXPORT alpm_option_set_dlcb(alpm_cb_download > cb) handle->dlcb = cb; > } > > +void SYMEXPORT alpm_option_set_fetchcb(alpm_cb_fetch cb) > +{ > + if (handle == NULL) { > + pm_errno = PM_ERR_HANDLE_NULL; > + return; > + } > + handle->fetchcb = cb; > +} > + > void SYMEXPORT alpm_option_set_totaldlcb(alpm_cb_totaldl cb) > { > if (handle == NULL) { > @@ -519,12 +528,6 @@ int SYMEXPORT alpm_option_remove_ignoregrp(const char > *grp) return(0); > } > > -void SYMEXPORT alpm_option_set_xfercommand(const char *cmd) > -{ > - if(handle->xfercommand) FREE(handle->xfercommand); > - if(cmd) handle->xfercommand = strdup(cmd); > -} > - > void SYMEXPORT alpm_option_set_nopassiveftp(unsigned short nopasv) > { > handle->nopassiveftp = nopasv; > diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h > index ad7666d..89fc457 100644 > --- a/lib/libalpm/handle.h > +++ b/lib/libalpm/handle.h > @@ -40,6 +40,7 @@ typedef struct _pmhandle_t { > alpm_cb_log logcb; /* Log callback function */ > alpm_cb_download dlcb; /* Download callback function */ > alpm_cb_totaldl totaldlcb; /* Total download callback function */ > + alpm_cb_fetch fetchcb; /* Download file callback function */ > > /* filesystem paths */ > char *root; /* Root path, default '/' */ > @@ -57,7 +58,6 @@ typedef struct _pmhandle_t { > /* options */ > unsigned short usesyslog; /* Use syslog instead of logfile? */ /* > TODO > move to frontend */ unsigned short nopassiveftp; /* Don't use PASV ftp > connections */ - char *xfercommand; /* External download command > */ > unsigned short usedelta; /* Download deltas if possible */ > } pmhandle_t; > > diff --git a/src/pacman/conf.h b/src/pacman/conf.h > index 466d983..650b0f9 100644 > --- a/src/pacman/conf.h > +++ b/src/pacman/conf.h > @@ -20,6 +20,11 @@ > #define _PM_CONF_H > > #include <alpm.h> > +#if defined(HAVE_SYS_SYSLIMITS_H) > +#include <sys/syslimits.h> /* PATH_MAX */ > +#else > +#define PATH_MAX 1024 > +#endif > > typedef struct __config_t { > unsigned short op; > @@ -71,6 +76,7 @@ typedef struct __config_t { > unsigned short cleanmethod; /* select -Sc behavior */ > alpm_list_t *holdpkg; > alpm_list_t *syncfirst; > + char xfercommand[PATH_MAX]; /* external download command */ > } config_t; > > /* Operations */ > diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c > index 59916d6..0d6c897 100644 > --- a/src/pacman/pacman.c > +++ b/src/pacman/pacman.c > @@ -573,6 +573,99 @@ static void setrepeatingoption(const char *ptr, const > char *option, pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, p); > } > > +/** External fetch callback */ > +static int _download_with_xfercommand(const char *url, const char > *localpath, + time_t mtimeold, time_t *mtimenew) { > + int ret = 0; > + int retval; > + int usepart = 0; > + char *ptr1, *ptr2; > + char origCmd[PATH_MAX]; > + char parsedCmd[PATH_MAX] = ""; > + char cwd[PATH_MAX]; > + char *destfile, *tempfile, *filename; > + int len; > + > + if(!config->xfercommand) { > + return -1; > + } > + > + filename = strrchr(url, '/'); > + if(!filename) { > + return -1; > + } else { > + filename++; /* omit leading slash */ > + } > + > + len = strlen(localpath) + strlen(filename) + 1; > + destfile = calloc(len, sizeof(*destfile)); > + snprintf(destfile, len, "%s%s", localpath, filename); > + > + len += 5; /* ".part" */ > + tempfile = calloc(len, sizeof(*tempfile)); > + snprintf(tempfile, len, "%s.part", destfile); > + > + strncpy(origCmd, config->xfercommand, sizeof(origCmd)); > + /* replace all occurrences of %o with fn.part */ > + ptr1 = origCmd; > + while((ptr2 = strstr(ptr1, "%o"))) { > + usepart = 1; > + ptr2[0] = '\0'; > + strcat(parsedCmd, ptr1); > + strcat(parsedCmd, tempfile); > + ptr1 = ptr2 + 2; > + } > + strcat(parsedCmd, ptr1); > + /* replace all occurrences of %u with the download URL */ > + strncpy(origCmd, parsedCmd, sizeof(origCmd)); > + parsedCmd[0] = '\0'; > + ptr1 = origCmd; > + while((ptr2 = strstr(ptr1, "%u"))) { > + ptr2[0] = '\0'; > + strcat(parsedCmd, ptr1); > + strcat(parsedCmd, url); > + ptr1 = ptr2 + 2; > + } > + strcat(parsedCmd, ptr1); > + /* cwd to the download directory */ > + getcwd(cwd, PATH_MAX); > + if(chdir(localpath)) { > + pm_printf(PM_LOG_DEBUG, "could not chdir to %s\n", localpath); > + ret = -1; > + goto cleanup; > + } > + /* execute the parsed command via /bin/sh -c */ > + pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedCmd); > + retval = system(parsedCmd); > + > + if(retval == -1) { > + pm_printf(PM_LOG_DEBUG, "running XferCommand: fork failed!\n"); > + ret = -1; > + } else if(retval != 0) { > + /* download failed */ > + pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero > status " > + "code (%d)\n", retval); > + ret = -1; > + } else { > + /* download was successful */ > + if(usepart) { > + rename(tempfile, destfile); > + } > + ret = 0; > + } > + > +cleanup: > + chdir(cwd); > + if(ret == -1) { > + /* hack to let an user the time to cancel a download */ > + sleep(2); > + } > + free(destfile); > + free(tempfile); > + > + return(ret); > +} > + > /* The real parseconfig. Called with a null section argument by the > publicly * visible parseconfig so we can recall from within ourself on an > include */ static int _parseconfig(const char *file, const char > *givensection, @@ -736,7 +829,8 @@ static int _parseconfig(const char > *file, const char *givensection, pm_printf(PM_LOG_DEBUG, "config: logfile: > %s\n", ptr); > } > } else if (strcmp(key, "XferCommand") > == 0) { > - > alpm_option_set_xfercommand(ptr); > + strncpy(config->xfercommand, > ptr, sizeof(config->xfercommand)); > + > alpm_option_set_fetchcb(_download_with_xfercommand); > pm_printf(PM_LOG_DEBUG, > "config: xfercommand: %s\n", ptr); > } else if (strcmp(key, "CleanMethod") > == 0) { > if (strcmp(ptr, > "KeepInstalled") == 0) { -- ------------------- Dario Freddi KDE Developer GPG Key Signature: 511A9A3B
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ pacman-dev mailing list [email protected] http://www.archlinux.org/mailman/listinfo/pacman-dev
