FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > ArchLinux > ArchLinux Pacman Development

 
 
LinkBack Thread Tools
 
Old 02-19-2009, 05:55 AM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

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 when if it is defined, otherwise the old
behavior applies.

Signed-off-by: Sebastian Nowicki <sebnow@gmail.com>
---
lib/libalpm/alpm.h | 14 ++++++++++++++
lib/libalpm/dload.c | 9 ++++++---
lib/libalpm/handle.c | 18 ++++++++++++++++++
lib/libalpm/handle.h | 1 +
4 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 7b7ca4e..266f7ff 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);

diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index 5b0a691..a244999 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -352,12 +352,15 @@ static int download(const char *url, const char *localpath,
int ret;

/* We have a few things to take into account here.
- * 1. If we have both internal/external available, choose based on
+ * 1. If the fetch callback is set, prefer it.
+ * 2. 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
+ * 3. 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) {
+ ret = handle->fetchcb(url, localpath, mtimeold, mtimenew);
+ } else if(handle->xfercommand == NULL) {
#if defined(INTERNAL_DOWNLOAD)
ret = download_internal(url, localpath, mtimeold, mtimenew);
#else
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 813f439..f19bc3f 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) {
@@ -258,6 +267,15 @@ void SYMEXPORT alpm_option_set_dlcb(alpm_cb_download cb)
handle->dlcb = cb;
}

+void 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) {
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index ad7666d..f895d85 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 '/' */
--
1.6.1

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-19-2009, 04:03 PM
Aaron Griffin
 
Default Add a fetch callback to allow front-end download support

On Thu, Feb 19, 2009 at 12:55 AM, Sebastian Nowicki <sebnow@gmail.com> wrote:
> 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 when if it is defined, otherwise the old
> behavior applies.

I like this, but my first thought is: why not extrapolate our current
downloading as a "fetch callback" too? That way the check just needs a
"!= NULL" before calling it, and it can be done on config parsing:

//in initialization
#ifdef INTERNAL_DOWNLOAD
fetchcb = internal_fetch;
#else
fetchcb = NULL;
#endif
...
...
// in config parsing
if(strcmp(blah, "XferCommand") == 0) {
fetchcb = use_xfercommand;
}
_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-19-2009, 06:11 PM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

On 20/02/2009, at 2:03 AM, Aaron Griffin wrote:

On Thu, Feb 19, 2009 at 12:55 AM, Sebastian Nowicki
<sebnow@gmail.com> wrote:
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 when if it is defined, otherwise the old
behavior applies.


Just noticed it should be s/when//.


I like this, but my first thought is: why not extrapolate our current
downloading as a "fetch callback" too? That way the check just needs a
"!= NULL" before calling it, and it can be done on config parsing:


I had the same idea, but decided to leave it as is so that the two
methods can be distinguished. Re-thinking it, they don't really need
to be distinguished (in alpm), since the callback is used if the front-
end specifies it either way, and the default could be the internal
download function. It's quite late atm so I won't send the patch just
now .



//in initialization
#ifdef INTERNAL_DOWNLOAD
fetchcb = internal_fetch;
#else
fetchcb = NULL;
#endif
...
...
// in config parsing
if(strcmp(blah, "XferCommand") == 0) {
fetchcb = use_xfercommand;
}


Indeed, much simpler. It seems this makes download() unecessary as it
would only call handle->fetchcb(), and as far as I can tell it only
gets called in _alpm_download_single_file() and alpm_fetch_pkgurl().


_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-19-2009, 06:36 PM
Aaron Griffin
 
Default Add a fetch callback to allow front-end download support

On Thu, Feb 19, 2009 at 1:11 PM, Sebastian Nowicki <sebnow@gmail.com> wrote:
>
> On 20/02/2009, at 2:03 AM, Aaron Griffin wrote:
>
>> On Thu, Feb 19, 2009 at 12:55 AM, Sebastian Nowicki <sebnow@gmail.com>
>> wrote:
>>>
>>> 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 when if it is defined, otherwise the old
>>> behavior applies.
>
> Just noticed it should be s/when//.
>
>> I like this, but my first thought is: why not extrapolate our current
>> downloading as a "fetch callback" too? That way the check just needs a
>> "!= NULL" before calling it, and it can be done on config parsing:
>
> I had the same idea, but decided to leave it as is so that the two methods
> can be distinguished. Re-thinking it, they don't really need to be
> distinguished (in alpm), since the callback is used if the front-end
> specifies it either way, and the default could be the internal download
> function. It's quite late atm so I won't send the patch just now .
>
>> //in initialization
>> #ifdef INTERNAL_DOWNLOAD
>> fetchcb = internal_fetch;
>> #else
>> fetchcb = NULL;
>> #endif
>> ...
>> ...
>> // in config parsing
>> if(strcmp(blah, "XferCommand") == 0) {
>> fetchcb = use_xfercommand;
>> }
>
> Indeed, much simpler. It seems this makes download() unecessary as it would
> only call handle->fetchcb(), and as far as I can tell it only gets called in
> _alpm_download_single_file() and alpm_fetch_pkgurl().

Yeah, we'd just need to make sure that there is a "if fetchcb == NULL)
{ error and return 1 }"
We don't want to fail early on this, as a download function isn't always needed
_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-20-2009, 06:21 AM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

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.

Signed-off-by: Sebastian Nowicki <sebnow@gmail.com>
---
lib/libalpm/alpm.h | 14 +++++++
lib/libalpm/dload.c | 101 +------------------------------------------------
lib/libalpm/handle.c | 18 +++++++++
lib/libalpm/handle.h | 1 +
src/pacman/conf.h | 6 +++
src/pacman/pacman.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++-
6 files changed, 137 insertions(+), 99 deletions(-)

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 7b7ca4e..266f7ff 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);

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] = '';
- 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] = '';
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%u"))) {
- ptr2[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
"), 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
", parsedCmd);
- retval = system(parsedCmd);
-
- if(retval == -1) {
- _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!
"));
- 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)
", 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..84e2c3f 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) {
@@ -258,6 +267,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) {
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index ad7666d..f895d85 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 '/' */
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
", 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] = '';
+ 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] = '';
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%u"))) {
+ ptr2[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
", localpath);
+ ret = -1;
+ goto cleanup;
+ }
+ /* execute the parsed command via /bin/sh -c */
+ pm_printf(PM_LOG_DEBUG, "running command: %s
", parsedCmd);
+ retval = system(parsedCmd);
+
+ if(retval == -1) {
+ pm_printf(PM_LOG_DEBUG, "running XferCommand: fork failed!
");
+ ret = -1;
+ } else if(retval != 0) {
+ /* download failed */
+ pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
+ "code (%d)
", 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
", 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
", ptr);
} else if (strcmp(key, "CleanMethod") == 0) {
if (strcmp(ptr, "KeepInstalled") == 0) {
--
1.6.1

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-20-2009, 06:28 AM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

I left the download() function to lazily initialize handle->fetchcb,
since it couldn't be done from _alpm_handle_new().

On Fri, Feb 20, 2009 at 4:21 PM, Sebastian Nowicki <sebnow@gmail.com> wrote:
> The external download method was moved to pacman and is set as the fetch
> callback, if the command is defined in the configuration file.

I'm not sure if this is what you meant. It seems like a bit change
(could break front-end code), but I didn't see any other way. I just
noticed I forgot to remove the xfercommand related stuff from libalpm.
Re-sending patch in a second.
_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-20-2009, 06:31 AM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

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 <sebnow@gmail.com>
---
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] = '';
- 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] = '';
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%u"))) {
- ptr2[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
"), 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
", parsedCmd);
- retval = system(parsedCmd);
-
- if(retval == -1) {
- _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!
"));
- 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)
", 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
", 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] = '';
+ 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] = '';
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%u"))) {
+ ptr2[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
", localpath);
+ ret = -1;
+ goto cleanup;
+ }
+ /* execute the parsed command via /bin/sh -c */
+ pm_printf(PM_LOG_DEBUG, "running command: %s
", parsedCmd);
+ retval = system(parsedCmd);
+
+ if(retval == -1) {
+ pm_printf(PM_LOG_DEBUG, "running XferCommand: fork failed!
");
+ ret = -1;
+ } else if(retval != 0) {
+ /* download failed */
+ pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
+ "code (%d)
", 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
", 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
", ptr);
} else if (strcmp(key, "CleanMethod") == 0) {
if (strcmp(ptr, "KeepInstalled") == 0) {
--
1.6.1

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-20-2009, 01:34 PM
Dario Freddi
 
Default Add a fetch callback to allow front-end download support

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 <sebnow@gmail.com>
> ---
> 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] = '';
> - 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] = '';
> - ptr1 = origCmd;
> - while((ptr2 = strstr(ptr1, "%u"))) {
> - ptr2[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
"), 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
", parsedCmd);
> - retval = system(parsedCmd);
> -
> - if(retval == -1) {
> - _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!
"));
> - 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)
", 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
", 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] = '';
> + 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] = '';
> + ptr1 = origCmd;
> + while((ptr2 = strstr(ptr1, "%u"))) {
> + ptr2[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
", localpath);
> + ret = -1;
> + goto cleanup;
> + }
> + /* execute the parsed command via /bin/sh -c */
> + pm_printf(PM_LOG_DEBUG, "running command: %s
", parsedCmd);
> + retval = system(parsedCmd);
> +
> + if(retval == -1) {
> + pm_printf(PM_LOG_DEBUG, "running XferCommand: fork failed!
");
> + ret = -1;
> + } else if(retval != 0) {
> + /* download failed */
> + pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
> + "code (%d)
", 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
", 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
", ptr);
> } else if (strcmp(key, "CleanMethod") == 0) {
> if (strcmp(ptr, "KeepInstalled") == 0) {

--
-------------------

Dario Freddi
KDE Developer
GPG Key Signature: 511A9A3B

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-20-2009, 03:30 PM
Aaron Griffin
 
Default Add a fetch callback to allow front-end download support

On Fri, Feb 20, 2009 at 8:34 AM, Dario Freddi <drf54321@gmail.com> wrote:
> 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.

Agreed - that's why I thought it was a good idea
_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 
Old 03-05-2009, 05:02 AM
Sebastian Nowicki
 
Default Add a fetch callback to allow front-end download support

Bump. Any changes required? I might be offline for a while soon, so
I'd just like to get an OK on it.


_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://www.archlinux.org/mailman/listinfo/pacman-dev
 

Thread Tools




All times are GMT. The time now is 07:42 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright ©2007 - 2008, www.linux-archive.org