[pacman-dev] [PATCH 3/4] Download delta files if UseDelta is set.

Nathan Jones nathanj at insightbb.com
Mon Oct 15 17:51:11 EDT 2007


Signed-off-by: Nathan Jones <nathanj at 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




More information about the pacman-dev mailing list