[pacman-dev] [PATCH] Complete rework of package accessor logic

Dan McGee dan at archlinux.org
Sun May 11 21:28:59 EDT 2008


Hopefully we've finally arrived at package handling nirvana, or at least
this commit will get us a hell of a lot closer. The former method of getting
the depends list for a package was the following:

1. call alpm_pkg_get_depends()
2. this method would check if the package came from the cache
3. if so, ensure our cache level is correct, otherwise call db_load
4. finally return the depends list

Why did this suck? Because getting the depends list from the package
shouldn't care about whether the package was loaded from a file, from the
'package cache', or some other system which we can't even use because the
damn thing is so complicated. It should just return the depends list.

So what does this commit change? It adds a pointer to a struct of function
pointers to every package for all of these 'package operations'  as I've
decided to call them (I know, sounds completely straightforward, right?). So
now when we call an alpm_pkg_get-* function, we don't do any of the cache
logic or anything else there- we let the actual backend handle it by
delegating all work to the method at pkg->ops->get_depends.

Now that be_package has achieved equal status with be_files, we can treat
packages from these completely different load points differently. We know a
package loaded from a pkg.tar.gz will have all of its fields populated, so
we can set up all its accessor functions to be direct accessors. On the
other hand, the packages loaded from the local and sync DBs are not always
fully-loaded, so their accessor functions are routed through the same logic
as before.

Net result? More code. However, this code now make it roughly 52 times
easier to open the door to something like a read-only tar.gz database
backend.

Are you still reading? I'm impressed. Looking at the patch will probably be
clearer than this long-winded explanation.

Signed-off-by: Dan McGee <dan at archlinux.org>
---
 lib/libalpm/be_files.c   |  383 +++++++++++++++++++++++++++++++++++++++++++++-
 lib/libalpm/be_package.c |    2 +
 lib/libalpm/package.c    |  327 +++++++++++-----------------------------
 lib/libalpm/package.h    |   61 +++++++-
 4 files changed, 527 insertions(+), 246 deletions(-)

diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
index b0f597d..c9e708d 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_files.c
@@ -1,8 +1,7 @@
 /*
  *  be_files.c
  *
- *  Copyright (c) 2006 by Christian Hamar <krics at linuxforum.hu>
- *  Copyright (c) 2006 by Miklos Vajna <vmiklos at frugalware.org>
+ *  Copyright (c) 2002-2008 by Judd Vinet <jvinet at zeroflux.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -46,6 +45,384 @@
 #include "deps.h"
 #include "dload.h"
 
+/* Cache-specific accessor functions. These implementations allow for lazy
+ * loading by the files backend when a data member is actually needed
+ * rather than loading all pieces of information when the package is first
+ * initialized.
+ */
+const char *_cache_get_filename(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+
+	return pkg->filename;
+}
+
+const char *_cache_get_name(pmpkg_t *pkg)
+{
+	/* Sanity checks */
+	ASSERT(pkg != NULL, return(NULL));
+
+	return pkg->name;
+}
+
+static const char *_cache_get_version(pmpkg_t *pkg)
+{
+	/* Sanity checks */
+	ASSERT(pkg != NULL, return(NULL));
+
+	return pkg->version;
+}
+
+static const char *_cache_get_desc(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->desc;
+}
+
+const char *_cache_get_url(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->url;
+}
+
+time_t _cache_get_builddate(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(0));
+	ASSERT(pkg != NULL, return(0));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->builddate;
+}
+
+time_t _cache_get_installdate(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(0));
+	ASSERT(pkg != NULL, return(0));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->installdate;
+}
+
+const char *_cache_get_packager(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->packager;
+}
+
+const char *_cache_get_md5sum(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->md5sum;
+}
+
+const char *_cache_get_arch(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->arch;
+}
+
+unsigned long _cache_get_size(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(-1));
+	ASSERT(pkg != NULL, return(-1));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->size;
+}
+
+unsigned long _cache_get_isize(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(-1));
+	ASSERT(pkg != NULL, return(-1));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->isize;
+}
+
+pmpkgreason_t _cache_get_reason(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(-1));
+	ASSERT(pkg != NULL, return(-1));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->reason;
+}
+
+alpm_list_t *_cache_get_licenses(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->licenses;
+}
+
+alpm_list_t *_cache_get_groups(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->groups;
+}
+
+alpm_list_t *_cache_get_depends(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DEPENDS)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
+	}
+	return pkg->depends;
+}
+
+alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DEPENDS)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
+	}
+	return pkg->optdepends;
+}
+
+alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DEPENDS)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
+	}
+	return pkg->conflicts;
+}
+
+alpm_list_t *_cache_get_provides(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DEPENDS)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
+	}
+	return pkg->provides;
+}
+
+alpm_list_t *_cache_get_replaces(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DESC)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
+	}
+	return pkg->replaces;
+}
+
+alpm_list_t *_cache_get_deltas(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(!(pkg->infolevel & INFRQ_DELTAS)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS);
+	}
+	return pkg->deltas;
+}
+
+
+alpm_list_t *_cache_get_files(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(pkg->origin == PKG_FROM_LOCALDB
+		 && !(pkg->infolevel & INFRQ_FILES)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
+	}
+	return pkg->files;
+}
+
+alpm_list_t *_cache_get_backup(pmpkg_t *pkg)
+{
+	ALPM_LOG_FUNC;
+
+	/* Sanity checks */
+	ASSERT(handle != NULL, return(NULL));
+	ASSERT(pkg != NULL, return(NULL));
+
+	if(pkg->origin == PKG_FROM_LOCALDB
+		 && !(pkg->infolevel & INFRQ_FILES)) {
+		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
+	}
+	return pkg->backup;
+}
+
+/** The sync database operations struct. Get package fields through
+ * lazy accessor methods that handle any backend loading and caching
+ * logic.
+ */
+static struct pkg_operations sync_pkg_ops = {
+	.get_filename    = _cache_get_filename,
+	.get_name        = _cache_get_name,
+	.get_version     = _cache_get_version,
+	.get_desc        = _cache_get_desc,
+	.get_url         = _cache_get_url,
+	.get_builddate   = _cache_get_builddate,
+	.get_installdate = _cache_get_installdate,
+	.get_packager    = _cache_get_packager,
+	.get_md5sum      = _cache_get_md5sum,
+	.get_arch        = _cache_get_arch,
+	.get_size        = _cache_get_size,
+	.get_isize       = _cache_get_isize,
+	.get_reason      = _cache_get_reason,
+	.get_licenses    = _cache_get_licenses,
+	.get_groups      = _cache_get_groups,
+	.get_depends     = _cache_get_depends,
+	.get_optdepends  = _cache_get_optdepends,
+	.get_conflicts   = _cache_get_conflicts,
+	.get_provides    = _cache_get_provides,
+	.get_replaces    = _cache_get_replaces,
+	.get_deltas      = _cache_get_deltas,
+	.get_files       = _cache_get_files,
+	.get_backup      = _cache_get_backup,
+};
+
+/** The local database operations struct. Get package fields through
+ * lazy accessor methods that handle any backend loading and caching
+ * logic.
+ */
+static struct pkg_operations local_pkg_ops = {
+	.get_filename    = _cache_get_filename,
+	.get_name        = _cache_get_name,
+	.get_version     = _cache_get_version,
+	.get_desc        = _cache_get_desc,
+	.get_url         = _cache_get_url,
+	.get_builddate   = _cache_get_builddate,
+	.get_installdate = _cache_get_installdate,
+	.get_packager    = _cache_get_packager,
+	.get_md5sum      = _cache_get_md5sum,
+	.get_arch        = _cache_get_arch,
+	.get_size        = _cache_get_size,
+	.get_isize       = _cache_get_isize,
+	.get_reason      = _cache_get_reason,
+	.get_licenses    = _cache_get_licenses,
+	.get_groups      = _cache_get_groups,
+	.get_depends     = _cache_get_depends,
+	.get_optdepends  = _cache_get_optdepends,
+	.get_conflicts   = _cache_get_conflicts,
+	.get_provides    = _cache_get_provides,
+	.get_replaces    = _cache_get_replaces,
+	.get_deltas      = _cache_get_deltas,
+	.get_files       = _cache_get_files,
+	.get_backup      = _cache_get_backup,
+};
 
 /*
  * Return the last update time as number of seconds from the epoch.
@@ -368,8 +745,10 @@ pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target)
 			/* TODO bad bad hack for now */
 			if(db == handle->db_local) {
 				pkg->origin = PKG_FROM_LOCALDB;
+				pkg->ops = &local_pkg_ops;
 			}  else {
 				pkg->origin = PKG_FROM_SYNCDB;
+				pkg->ops = &sync_pkg_ops;
 			}
 			pkg->origin_data.db = db;
 		}
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index bee0635..93965db 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -229,7 +229,9 @@ static pmpkg_t *pkg_load(const char *pkgfile, unsigned short full)
 
 	/* internal fields for package struct */
 	newpkg->origin = PKG_FROM_FILE;
+	/* TODO eventually kill/move this? */
 	newpkg->origin_data.file = strdup(pkgfile);
+	newpkg->ops = &default_pkg_ops;
 
 	if(full) {
 		/* "checking for conflicts" requires a sorted list, ensure that here */
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 2e84f3b..c226a64 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -1,10 +1,7 @@
 /*
  *  package.c
  *
- *  Copyright (c) 2002-2007 by Judd Vinet <jvinet at zeroflux.org>
- *  Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
- *  Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
- *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at frugalware.org>
+ *  Copyright (c) 2002-2008 by Judd Vinet <jvinet at zeroflux.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -112,329 +109,180 @@ int SYMEXPORT alpm_pkg_vercmp(const char *ver1, const char *ver2)
 	return(_alpm_versioncmp(ver1, ver2));
 }
 
+/* Default package accessor functions. These will get overridden by any
+ * backend logic that needs lazy access, such as the local database through
+ * a lazy-laod cache. However, the defaults will work just fine for fully-
+ * populated package structures. */
+const char *_pkg_get_filename(pmpkg_t *pkg)    { return pkg->filename; }
+const char *_pkg_get_name(pmpkg_t *pkg)        { return pkg->name; }
+const char *_pkg_get_version(pmpkg_t *pkg)     { return pkg->version; }
+const char *_pkg_get_desc(pmpkg_t *pkg)        { return pkg->desc; }
+const char *_pkg_get_url(pmpkg_t *pkg)         { return pkg->url; }
+time_t _pkg_get_builddate(pmpkg_t *pkg)        { return pkg->builddate; }
+time_t _pkg_get_installdate(pmpkg_t *pkg)      { return pkg->installdate; }
+const char *_pkg_get_packager(pmpkg_t *pkg)    { return pkg->packager; }
+const char *_pkg_get_md5sum(pmpkg_t *pkg)      { return pkg->md5sum; }
+const char *_pkg_get_arch(pmpkg_t *pkg)        { return pkg->arch; }
+unsigned long _pkg_get_size(pmpkg_t *pkg)      { return pkg->size; }
+unsigned long _pkg_get_isize(pmpkg_t *pkg)     { return pkg->isize; }
+pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg)    { return pkg->reason; }
+
+alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg)   { return pkg->licenses; }
+alpm_list_t *_pkg_get_groups(pmpkg_t *pkg)     { return pkg->groups; }
+alpm_list_t *_pkg_get_depends(pmpkg_t *pkg)    { return pkg->depends; }
+alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; }
+alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg)  { return pkg->conflicts; }
+alpm_list_t *_pkg_get_provides(pmpkg_t *pkg)   { return pkg->provides; }
+alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg)   { return pkg->replaces; }
+alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg)     { return pkg->deltas; }
+alpm_list_t *_pkg_get_files(pmpkg_t *pkg)      { return pkg->files; }
+alpm_list_t *_pkg_get_backup(pmpkg_t *pkg)     { return pkg->backup; }
+
+/** The standard package operations struct. Get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ */
+struct pkg_operations default_pkg_ops = {
+	.get_filename    = _pkg_get_filename,
+	.get_name        = _pkg_get_name,
+	.get_version     = _pkg_get_version,
+	.get_desc        = _pkg_get_desc,
+	.get_url         = _pkg_get_url,
+	.get_builddate   = _pkg_get_builddate,
+	.get_installdate = _pkg_get_installdate,
+	.get_packager    = _pkg_get_packager,
+	.get_md5sum      = _pkg_get_md5sum,
+	.get_arch        = _pkg_get_arch,
+	.get_size        = _pkg_get_size,
+	.get_isize       = _pkg_get_isize,
+	.get_reason      = _pkg_get_reason,
+	.get_licenses    = _pkg_get_licenses,
+	.get_groups      = _pkg_get_groups,
+	.get_depends     = _pkg_get_depends,
+	.get_optdepends  = _pkg_get_optdepends,
+	.get_conflicts   = _pkg_get_conflicts,
+	.get_provides    = _pkg_get_provides,
+	.get_replaces    = _pkg_get_replaces,
+	.get_deltas      = _pkg_get_deltas,
+	.get_files       = _pkg_get_files,
+	.get_backup      = _pkg_get_backup,
+};
+
+/* Public functions for getting package information. These functions
+ * delegate the hard work to the function callbacks attached to each
+ * package, which depend on where the package was loaded from. */
 const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-
-	return pkg->filename;
+	return pkg->ops->get_filename(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_BASE)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
-	}
-	return pkg->name;
+	return pkg->ops->get_name(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_BASE)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
-	}
-	return pkg->version;
+	return pkg->ops->get_version(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_desc(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->desc;
+	return pkg->ops->get_desc(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_url(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->url;
+	return pkg->ops->get_url(pkg);
 }
 
 time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(0));
-	ASSERT(pkg != NULL, return(0));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->builddate;
+	return pkg->ops->get_builddate(pkg);
 }
 
 time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(0));
-	ASSERT(pkg != NULL, return(0));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->installdate;
+	return pkg->ops->get_installdate(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_packager(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->packager;
+	return pkg->ops->get_packager(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->md5sum;
+	return pkg->ops->get_md5sum(pkg);
 }
 
 const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->arch;
+	return pkg->ops->get_arch(pkg);
 }
 
 unsigned long SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(-1));
-	ASSERT(pkg != NULL, return(-1));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->size;
+	return pkg->ops->get_size(pkg);
 }
 
 unsigned long SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(-1));
-	ASSERT(pkg != NULL, return(-1));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->isize;
+	return pkg->ops->get_isize(pkg);
 }
 
 pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(-1));
-	ASSERT(pkg != NULL, return(-1));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->reason;
+	return pkg->ops->get_reason(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->licenses;
+	return pkg->ops->get_licenses(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->groups;
+	return pkg->ops->get_groups(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_depends(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DEPENDS)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
-	}
-	return pkg->depends;
+	return pkg->ops->get_depends(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DEPENDS)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
-	}
-	return pkg->optdepends;
+	return pkg->ops->get_optdepends(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DEPENDS)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
-	}
-	return pkg->conflicts;
+	return pkg->ops->get_conflicts(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DEPENDS)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
-	}
-	return pkg->provides;
+	return pkg->ops->get_provides(pkg);
 }
 
-alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DELTAS)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS);
-	}
-	return pkg->deltas;
+	return pkg->ops->get_replaces(pkg);
 }
 
-alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & INFRQ_DESC)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
-	}
-	return pkg->replaces;
+	return pkg->ops->get_deltas(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_files(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin == PKG_FROM_LOCALDB
-		 && !(pkg->infolevel & INFRQ_FILES)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
-	}
-	return pkg->files;
+	return pkg->ops->get_files(pkg);
 }
 
 alpm_list_t SYMEXPORT *alpm_pkg_get_backup(pmpkg_t *pkg)
 {
-	ALPM_LOG_FUNC;
-
-	/* Sanity checks */
-	ASSERT(handle != NULL, return(NULL));
-	ASSERT(pkg != NULL, return(NULL));
-
-	if(pkg->origin == PKG_FROM_LOCALDB
-		 && !(pkg->infolevel & INFRQ_FILES)) {
-		_alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
-	}
-	return pkg->backup;
+	return pkg->ops->get_backup(pkg);
 }
 
 /**
@@ -756,6 +604,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
 
 	/* internal */
 	newpkg->origin = pkg->origin;
+	newpkg->ops = pkg->ops;
 	if(newpkg->origin == PKG_FROM_FILE) {
 		newpkg->origin_data.file = strdup(pkg->origin_data.file);
 	} else {
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index 6027021..a40c2a3 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -1,11 +1,7 @@
 /*
  *  package.h
  *
- *  Copyright (c) 2002-2007 by Judd Vinet <jvinet at zeroflux.org>
- *  Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
- *  Copyright (c) 2006 by David Kimpe <dnaku at frugalware.org>
- *  Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
- *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at frugalware.org>
+ *  Copyright (c) 2002-2008 by Judd Vinet <jvinet at zeroflux.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -34,6 +30,59 @@ typedef enum _pmpkgfrom_t {
 	PKG_FROM_SYNCDB
 } pmpkgfrom_t;
 
+/** Package operations struct. This struct contains function pointers to
+ * all methods used to access data in a package to allow for things such
+ * as lazy package intialization (such as used by the file backend). Each
+ * backend is free to define a stuct containing pointers to a specific
+ * implementation of these methods. Some backends may find using the
+ * defined default_pkg_ops struct to work just fine for their needs.
+ */
+struct pkg_operations {
+	const char *(*get_filename) (pmpkg_t *);
+	const char *(*get_name) (pmpkg_t *);
+	const char *(*get_version) (pmpkg_t *);
+	const char *(*get_desc) (pmpkg_t *);
+	const char *(*get_url) (pmpkg_t *);
+	time_t (*get_builddate) (pmpkg_t *);
+	time_t (*get_installdate) (pmpkg_t *);
+	const char *(*get_packager) (pmpkg_t *);
+	const char *(*get_md5sum) (pmpkg_t *);
+	const char *(*get_arch) (pmpkg_t *);
+	unsigned long (*get_size) (pmpkg_t *);
+	unsigned long (*get_isize) (pmpkg_t *);
+	pmpkgreason_t (*get_reason) (pmpkg_t *);
+
+	alpm_list_t *(*get_licenses) (pmpkg_t *);
+	alpm_list_t *(*get_groups) (pmpkg_t *);
+	alpm_list_t *(*get_depends) (pmpkg_t *);
+	alpm_list_t *(*get_optdepends) (pmpkg_t *);
+	alpm_list_t *(*get_conflicts) (pmpkg_t *);
+	alpm_list_t *(*get_provides) (pmpkg_t *);
+	alpm_list_t *(*get_replaces) (pmpkg_t *);
+	alpm_list_t *(*get_deltas) (pmpkg_t *);
+	alpm_list_t *(*get_files) (pmpkg_t *);
+	alpm_list_t *(*get_backup) (pmpkg_t *);
+
+	void *(*changelog_open) (pmpkg_t *);
+	size_t (*changelog_read) (void *, size_t, const pmpkg_t *, const void *);
+	int (*changelog_close) (const pmpkg_t *, void *);
+
+	/* still to add:
+	 * free()
+	 * dup()
+	 * checkmd5sum() ?
+	 * has_scriptlet()
+	 * compute_requiredby()
+	 */
+};
+
+/** The standard package operations struct. get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ * The actual definition is in package.c so it can have access to the
+ * default accessor functions which are defined there.
+ */
+extern struct pkg_operations default_pkg_ops;
+
 struct __pmpkg_t {
 	char *filename;
 	char *name;
@@ -73,6 +122,8 @@ struct __pmpkg_t {
 	pmdbinfrq_t infolevel;
 	unsigned long download_size;
 	alpm_list_t *delta_path;
+
+	struct pkg_operations *ops;
 };
 
 int _alpm_versioncmp(const char *a, const char *b);
-- 
1.5.5.1





More information about the pacman-dev mailing list