Signed-off-by: Nathan Jones <nathanj@insightbb.com> --- lib/libalpm/alpm.h | 1 + lib/libalpm/handle.c | 6 +++ lib/libalpm/handle.h | 1 + lib/libalpm/sync.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++- src/pacman/pacman.c | 3 + 5 files changed, 124 insertions(+), 2 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 527822d..85c0905 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -138,6 +138,7 @@ 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); pmdb_t *alpm_option_get_localdb(); alpm_list_t *alpm_option_get_syncdbs(); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index e8f2147..242bbe5 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -64,6 +64,7 @@ pmhandle_t *_alpm_handle_new() handle->cachedirs = NULL; handle->lockfile = NULL; handle->logfile = NULL; + handle->usedelta = 0; return(handle); } @@ -496,4 +497,9 @@ void SYMEXPORT alpm_option_set_nopassiveftp(unsigned short nopasv) handle->nopassiveftp = nopasv; } +void SYMEXPORT alpm_option_set_usedelta(unsigned short usedelta) +{ + handle->usedelta = usedelta; +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index cf2e9d5..d8edf00 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -61,6 +61,7 @@ typedef struct _pmhandle_t { unsigned short nopassiveftp; /* Don't use PASV ftp connections */ time_t upgradedelay; /* Time to wait before upgrading a package */ char *xfercommand; /* External download command */ + unsigned short usedelta; /* Download deltas if possible */ } pmhandle_t; extern pmhandle_t *handle; diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index d24a1e5..8aa197d 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -48,6 +48,7 @@ #include "handle.h" #include "alpm.h" #include "server.h" +#include "delta.h" pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) { @@ -700,9 +701,54 @@ cleanup: return(ret); } +/** Returns a list of deltas that should be downloaded instead of the + * package. + * + * Then it tests if a delta path exists between the currently installed + * version (if any) and the version to upgrade to. If so, the delta path + * is used if its size is below a set percentage of the package size, + * Otherwise, an empty list is returned. + * + * @param newpkg the new package to upgrade to + * @param db_local the local database + * + * @return the list of pmdelta_t * objects. NULL (the empty list) is + * returned if the package should be downloaded instead of deltas. + */ +static alpm_list_t *pkg_upgrade_delta_path(pmpkg_t *newpkg, pmdb_t *db_local) +{ + pmpkg_t *oldpkg = alpm_db_get_pkg(db_local, newpkg->name); + + if(oldpkg) { + const char *oldname = alpm_pkg_get_filename(oldpkg); + char *oldpath = _alpm_filecache_find(oldname); + + if(oldpath) { + alpm_list_t *deltas = alpm_shortest_delta_path( + alpm_pkg_get_deltas(newpkg), + alpm_pkg_get_version(oldpkg), + alpm_pkg_get_version(newpkg)); + + if(deltas) { + unsigned long dltsize = _alpm_delta_path_size(deltas); + unsigned long pkgsize = alpm_pkg_get_size(newpkg); + + if(dltsize < pkgsize * 0.7) { + return deltas; + } else { + alpm_list_free(deltas); + } + } + } + } + + return NULL; +} + int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) { alpm_list_t *i, *j, *files = NULL; + alpm_list_t *patches = NULL; pmtrans_t *tr = NULL; int replaces = 0, retval = 0; const char *cachedir = NULL; @@ -733,8 +779,39 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) } else { char *fpath = _alpm_filecache_find(fname); if(!fpath) { - /* file is not in the cache dir, so add it to the list */ - files = alpm_list_add(files, strdup(fname)); + if(handle->usedelta) { + alpm_list_t *delta_path = pkg_upgrade_delta_path(spkg, db_local); + + if(delta_path) { + alpm_list_t *dlts = NULL; + + for(dlts = delta_path; dlts; dlts = alpm_list_next(dlts)) { + pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts); + char *fpath2 = _alpm_filecache_find(d->filename); + + if(!fpath2) { + /* add the delta filename to the download list if + * it's not in the cache*/ + files = alpm_list_add(files, strdup(d->filename)); + } + + /* save the pkg and delta so that the xdelta patch + * command can be run after the downloads finish */ + patches = alpm_list_add(patches, spkg); + patches = alpm_list_add(patches, d); + } + + alpm_list_free(delta_path); + delta_path = NULL; + } else { + /* no deltas to download, so add the file to the + * download list */ + files = alpm_list_add(files, strdup(fname)); + } + } else { + /* not using deltas, so add the file to the download list */ + files = alpm_list_add(files, strdup(fname)); + } } FREE(fpath); } @@ -750,6 +827,40 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) } FREELIST(files); } + + if(handle->usedelta) { + /* now apply any deltas that have been downloaded */ + alpm_list_t *p = patches; + while(p) { + pmpkg_t *pkg; + pmdelta_t *d; + char command[512]; + + pkg = alpm_list_getdata(p); + p = alpm_list_next(p); + + d = alpm_list_getdata(p); + p = alpm_list_next(p); + + snprintf(command, 512, + "xdelta patch %s/%s %s/%s-%s-%s.pkg.tar.gz %s/%s-%s-%s.pkg.tar.gz", + cachedir, d->filename, + cachedir, pkg->name, d->from, pkg->arch, + cachedir, pkg->name, d->to, pkg->arch); + _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command); + + printf("Generating %s-%s-%s.pkg.tar.gz with %s... ", + pkg->name, d->to, pkg->arch, d->filename); + if(system(command) == 0) { + printf("done.\n"); + } else { + printf("failed.\n"); + } + } + + alpm_list_free(patches); + patches = NULL; + } } if(trans->flags & PM_TRANS_FLAG_PRINTURIS) { return(0); diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 8474020..2f6f928 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -548,6 +548,9 @@ static int _parseconfig(const char *file, const char *givensection, } else if(strcmp(key, "ShowSize") == 0 || strcmp(upperkey, "SHOWSIZE") == 0) { config->showsize = 1; pm_printf(PM_LOG_DEBUG, "config: showsize\n"); + } else if(strcmp(key, "UseDelta") == 0 || strcmp(upperkey, "USEDELTA") == 0) { + alpm_option_set_usedelta(1); + pm_printf(PM_LOG_DEBUG, "config: usedelta\n"); } else { pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' not recognized.\n"), file, linenum, key); -- 1.5.3.4