Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Jul 2013 11:55:21 GMT
From:      mattbw@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r254408 - in soc2013/mattbw/backend: . actions query
Message-ID:  <201307081155.r68BtLlK042448@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mattbw
Date: Mon Jul  8 11:55:21 2013
New Revision: 254408
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=254408

Log:
  so many query changes while FreeBSD.org was down...

Added:
  soc2013/mattbw/backend/query/
  soc2013/mattbw/backend/query/core.c
     - copied, changed from r254407, soc2013/mattbw/backend/query.c
  soc2013/mattbw/backend/query/core.h
     - copied, changed from r254407, soc2013/mattbw/backend/query.h
  soc2013/mattbw/backend/query/do.c
  soc2013/mattbw/backend/query/do.h
  soc2013/mattbw/backend/query/match.c
  soc2013/mattbw/backend/query/match.h
Replaced:
  soc2013/mattbw/backend/query.h
Deleted:
  soc2013/mattbw/backend/query.c
  soc2013/mattbw/backend/query_match.c
  soc2013/mattbw/backend/query_match.h
Modified:
  soc2013/mattbw/backend/Makefile
  soc2013/mattbw/backend/actions/get-details.c
  soc2013/mattbw/backend/actions/get-files.c
  soc2013/mattbw/backend/actions/get-repo-list.c
  soc2013/mattbw/backend/actions/install-files.c
  soc2013/mattbw/backend/actions/install-packages.c
  soc2013/mattbw/backend/actions/resolve.c
  soc2013/mattbw/backend/utils.h

Modified: soc2013/mattbw/backend/Makefile
==============================================================================
--- soc2013/mattbw/backend/Makefile	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/Makefile	Mon Jul  8 11:55:21 2013	(r254408)
@@ -8,8 +8,6 @@
 		groups.c			\
 		licenses.c			\
 		pkgutils.c			\
-		query.c				\
-		query_match.c			\
 		utils.c
 SRCS+=						\
 		actions/get-details.c		\
@@ -19,6 +17,11 @@
 		actions/install-packages.c	\
 		actions/resolve.c
 
+SRCS+=						\
+		query/core.c			\
+		query/do.c			\
+		query/match.c
+
 LIBDIR=		/usr/local/lib/packagekit-backend
 
 PKGS= 		pkg gio-2.0 gio-unix-2.0

Modified: soc2013/mattbw/backend/actions/get-details.c
==============================================================================
--- soc2013/mattbw/backend/actions/get-details.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/get-details.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -23,8 +23,8 @@
 #include "pkg.h"
 
 #include "../groups.h"		/* group_from_origin */
-#include "../query_match.h"	/* query_match_... */
 #include "../licenses.h"	/* license_from_pkg */
+#include "../query.h"		/* query_... */
 
 #include "actions.h"		/* get_details_thread prototype */
 
@@ -39,8 +39,11 @@
 gboolean
 get_details_thread(PkBackend *backend)
 {
+	gboolean	success;
 
-	return query_match_id_to_emitter(backend, LOAD_FLAGS, emit);
+	success = query_match_id_to_emitter(backend, LOAD_FLAGS, emit);
+	pk_backend_finished(backend);
+	return success;
 }
 
 /*
@@ -49,25 +52,31 @@
 static gboolean
 emit(struct pkg *pkg, const gchar *id, struct query *q)
 {
+	gboolean	success;
 	const char     *description;
 	const char     *origin;
 	const char     *www;
 	int64_t		flatsize;
 
+	query_set_percentage(q, 0);
+
 	/* Information not already part of the PackageID */
 	description = origin = www = NULL;
 	flatsize = 0;
 	pkg_get(pkg,
-		PKG_DESC, &description,
-		PKG_FLATSIZE, &flatsize,
-		PKG_ORIGIN, &origin,
-		PKG_WWW, &www);
-
-	return pk_backend_details(query_backend(q),
-				  id,
-				  license_name_from_pkg(pkg),
-				  group_from_origin(origin),
-				  description,
-				  www,
-				  flatsize);
+	    PKG_DESC, &description,
+	    PKG_FLATSIZE, &flatsize,
+	    PKG_ORIGIN, &origin,
+	    PKG_WWW, &www);
+
+	success = pk_backend_details(query_backend(q),
+	    id,
+	    license_name_from_pkg(pkg),
+	    group_from_origin(origin),
+	    description,
+	    www,
+	    flatsize);
+
+	query_set_percentage(q, 100);
+	return success;
 }

Modified: soc2013/mattbw/backend/actions/get-files.c
==============================================================================
--- soc2013/mattbw/backend/actions/get-files.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/get-files.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -26,8 +26,8 @@
 
 #include "../groups.h"		/* group_from_origin */
 #include "../hash_traverse.h"	/* HASH_FOR */
-#include "../query_match.h"	/* query_match_... */
 #include "../licenses.h"	/* license_from_pkg */
+#include "../query.h"		/* query_... */
 
 #include "actions.h"		/* get_files_thread prototype */
 
@@ -43,9 +43,13 @@
 gboolean
 get_files_thread(PkBackend *backend)
 {
+	gboolean success;
 
 	(void)pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
-	return query_match_id_to_emitter(backend, LOAD_FLAGS, emit);
+	success = query_match_id_to_emitter(backend, LOAD_FLAGS, emit);
+
+	(void)pk_backend_finished(backend);
+	return success;
 }
 
 /*
@@ -59,6 +63,8 @@
 	struct pkg_file *file;
 	struct sbuf    *sb;
 
+	query_set_percentage(q, 0);
+
 	success = FALSE;
 	file = NULL;
 
@@ -86,5 +92,6 @@
 	}
 
 	sbuf_delete(sb);
+	query_set_percentage(q, 100);
 	return success;
 }

Modified: soc2013/mattbw/backend/actions/get-repo-list.c
==============================================================================
--- soc2013/mattbw/backend/actions/get-repo-list.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/get-repo-list.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -38,8 +38,7 @@
 	repo = NULL;
 
 	(void)pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
-	(void)pk_backend_set_percentage(backend,
-	    PK_BACKEND_PERCENTAGE_INVALID);
+	(void)pk_backend_set_percentage(backend, 0);
 
 	for (HASH_FOR(err, pkg_repos, &repo))
 		pk_backend_repo_detail(backend,
@@ -47,6 +46,7 @@
 				       pkg_repo_name(repo),
 				       pkg_repo_enabled(repo));
 
+	(void)pk_backend_set_percentage(backend, 100);
 	(void)pk_backend_finished(backend);
 
 	return (err == EPKG_END ? TRUE : FALSE);

Modified: soc2013/mattbw/backend/actions/install-files.c
==============================================================================
--- soc2013/mattbw/backend/actions/install-files.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/install-files.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -25,7 +25,6 @@
 #include "../db.h"		/* db_open_remote */
 #include "../hash_traverse.h"	/* HASH_FOR */
 #include "../pkgutils.h"	/* pkgutils_... */
-#include "../query_match.h"	/* query_match_... */
 #include "../utils.h"		/* INTENTIONALLY_IGNORE */
 
 #include "actions.h"		/* install_files_thread prototype */

Modified: soc2013/mattbw/backend/actions/install-packages.c
==============================================================================
--- soc2013/mattbw/backend/actions/install-packages.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/install-packages.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -24,16 +24,14 @@
 
 #include "../hash_traverse.h"	/* HASH_FOR */
 #include "../pkgutils.h"	/* pkgutils_... */
-#include "../query_match.h"	/* query_match_... */
+#include "../query.h"		/* query_... */
 #include "../utils.h"		/* INTENTIONALLY_IGNORE */
 
 #include "actions.h"		/* install_packages_thread prototype */
 
-static gboolean	do_install_packages(struct pkg_jobs *jobs, struct query *q, gboolean simulate);
-static gboolean	do_install_solved_job(struct pkg_jobs *jobs, PkBackend *backend, gboolean simulate);
-static gboolean	do_install_solved_job_real(struct pkg_jobs *jobs, PkBackend *backend);
 static gboolean	job(struct pkg_jobs *jobs, struct query *q);
 static gboolean	sim_job(struct pkg_jobs *jobs, struct query *q);
+static gboolean	solve_job(struct query *q, struct pkg_jobs *jobs);
 static int	install_event_cb(void *backend_v, struct pkg_event *event);
 
 
@@ -44,9 +42,13 @@
 gboolean
 install_packages_thread(PkBackend *backend)
 {
+	gboolean	success;
+
+	(void)pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
+	success = query_match_id_to_job(backend, PKG_JOBS_INSTALL, job);
 
-	pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
-	return query_match_id_to_job(backend, PKG_JOBS_INSTALL, job);
+	(void)pk_backend_finished(backend);
+	return success;
 }
 
 /*
@@ -56,107 +58,107 @@
 gboolean
 simulate_install_packages_thread(PkBackend *backend)
 {
+	gboolean	success;
+
+	(void)pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
+	success = query_match_id_to_job(backend, PKG_JOBS_INSTALL, sim_job);
 
-	return query_match_id_to_job(backend, PKG_JOBS_INSTALL, sim_job);
+	(void)pk_backend_finished(backend);
+	return success;
 }
 
 /*
- * Installs (or pretends to install) an unsolved installation job.
+ * Tries to process the given solved installation jobs.
  */
 static gboolean
-do_install_packages(struct pkg_jobs *jobs, struct query *q, gboolean simulate)
+job(struct pkg_jobs *jobs, struct query *q)
 {
 	gboolean	success;
 	PkBackend      *backend;
 
 	success = FALSE;
 	backend = query_backend(q);
+	query_set_percentage(q, 0);
 
-	pk_backend_set_status(backend, PK_STATUS_ENUM_DEP_RESOLVE);
-	if (pkg_jobs_solve(jobs) != EPKG_OK)
-		pk_backend_error_code(backend,
-		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
-		    "could not solve the job");
-	else if (pkg_jobs_count(jobs) == 0)
+	if (solve_job(q, jobs) == FALSE)
+		goto cleanup;
+
+	pkg_event_register(install_event_cb, backend);
+
+	pk_backend_set_status(backend, PK_STATUS_ENUM_INSTALL);
+	if (pkg_jobs_apply(jobs) != EPKG_OK) {
 		pk_backend_error_code(backend,
-		    PK_ERROR_ENUM_INTERNAL_ERROR,
-		    "job contains no packages");
-	else
-		success = do_install_solved_job(jobs, backend, simulate);
+		    PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL,
+		    "job failed");
+		goto cleanup;
+	}
+	success = TRUE;
 
+cleanup:
+	pkg_event_register(NULL, NULL);
+	query_set_percentage(q, 100);
 	return success;
 }
 
 /*
- * Installs (or pretends to install) a fully solved installation job.
+ * Tries to simulate processing the given installation jobs.
  */
 static gboolean
-do_install_solved_job(struct pkg_jobs *jobs,
-    PkBackend *backend,
-    gboolean simulate)
+sim_job(struct pkg_jobs *jobs, struct query *q)
 {
 	gboolean	success;
+	PkBackend      *backend;
 	struct pkg     *pkg;
 
-	success = TRUE;
+	backend = query_backend(q);
+	success = FALSE;
+	query_set_percentage(q, 0);
+
+	if (solve_job(q, jobs) == FALSE)
+		goto cleanup;
+
+	pk_backend_set_status(backend, PK_STATUS_ENUM_RUNNING);
 	pkg = NULL;
 	while (pkg_jobs(jobs, &pkg) == EPKG_OK)
 		pkgutils_emit(pkg,
 		    backend,
 		    pkgutils_pkg_install_state(pkg));
 
-	if (simulate == FALSE)
-		success = do_install_solved_job_real(jobs, backend);
+	success = TRUE;
 
+cleanup:
+	query_set_percentage(q, 100);
 	return success;
 }
 
 /*
- * Actually installs a fully solved installation job.
+ * Solves a job and ensures it has packages available.
  */
 static gboolean
-do_install_solved_job_real(struct pkg_jobs *jobs, PkBackend *backend)
+solve_job(struct query *q, struct pkg_jobs *jobs)
 {
 	gboolean	success;
+	PkBackend      *backend;
 
 	success = FALSE;
+	backend = query_backend(q);
 
-	pkg_event_register(install_event_cb, backend);
-
-	pk_backend_set_status(backend, PK_STATUS_ENUM_INSTALL);
-	if (pkg_jobs_apply(jobs) == EPKG_OK)
-		success = TRUE;
-	else
+	pk_backend_set_status(backend, PK_STATUS_ENUM_DEP_RESOLVE);
+	if (pkg_jobs_solve(jobs) != EPKG_OK)
 		pk_backend_error_code(backend,
-		    PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL,
-		    "job failed");
-
-	pkg_event_register(NULL, NULL);
+		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
+		    "could not solve the job");
+	else if (pkg_jobs_count(jobs) == 0)
+		pk_backend_error_code(backend,
+		    PK_ERROR_ENUM_INTERNAL_ERROR,
+		    "job contains no packages");
+	else
+		success = TRUE;
 
 	return success;
 }
 
 /*
- * Tries to process the given solved installation jobs.
- */
-static gboolean
-job(struct pkg_jobs *jobs, struct query *q)
-{
-
-	return do_install_packages(jobs, q, FALSE);
-}
-
-/*
- * Tries to simulate processing the given installation jobs.
- */
-static gboolean
-sim_job(struct pkg_jobs *jobs, struct query *q)
-{
-
-	return do_install_packages(jobs, q, TRUE);
-}
-
-/*
  * Event handler for events emitted by pkg during an installation.
  */
 static int
@@ -199,9 +201,15 @@
 		    PK_INFO_ENUM_FINISHED);
 		break;
 	case PKG_EVENT_ERROR:
+		/*
+		 * This is sometimes used for nonfatal errors, so we can't
+		 * throw an error code here
+		 */
+#if 0
 		pk_backend_error_code(backend,
 		    PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL,
 		    event->e_pkg_error.msg);
+#endif
 		break;
 	case PKG_EVENT_FILE_MISMATCH:
 		pk_backend_error_code(backend,

Modified: soc2013/mattbw/backend/actions/resolve.c
==============================================================================
--- soc2013/mattbw/backend/actions/resolve.c	Mon Jul  8 07:12:20 2013	(r254407)
+++ soc2013/mattbw/backend/actions/resolve.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -22,6 +22,7 @@
 #include "pkg.h"
 
 #include "../db.h"		/* db_open_remote */
+#include "../query.h"		/* query_* */
 #include "actions.h"		/* Prototype */
 
 static gboolean	resolve_id(struct pkgdb *db, PkBackend *backend, gchar *id);
@@ -55,6 +56,7 @@
 	} else
 		success = FALSE;
 	
+	pkgdb_close(db);
 	pk_backend_finished(backend);
 	return success;
 }
@@ -64,6 +66,15 @@
 {
 
 	/* TODO: implement */
+
+	/*struct query_target t;
+
+	t.type = QUERY_EMIT;
+	t.data.emit.load_flags = load_flags;
+	t.data.emit.f = emitter;
+
+	return query_do(backend, &t, query_find_match);*/
+
 	(void)db;
 	(void)backend;
 	(void)id;

Added: soc2013/mattbw/backend/query.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2013/mattbw/backend/query.h	Mon Jul  8 11:55:21 2013	(r254408)
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (C) 2013 Matt Windsor <mattbw@FreeBSD.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _PKGNG_BACKEND_QUERY_H_
+#define _PKGNG_BACKEND_QUERY_H_
+
+/* Meta-header for the public interfaces to the query system. */
+
+#include "query/do.h"		/* query_do_... */
+#include "query/match.h"	/* query_match_... */
+
+#endif				/* !_PKGNG_BACKEND_QUERY_H_ */

Copied and modified: soc2013/mattbw/backend/query/core.c (from r254407, soc2013/mattbw/backend/query.c)
==============================================================================
--- soc2013/mattbw/backend/query.c	Mon Jul  8 07:12:20 2013	(r254407, copy source)
+++ soc2013/mattbw/backend/query/core.c	Mon Jul  8 11:55:21 2013	(r254408)
@@ -20,38 +20,52 @@
 
 #include <string.h>
 #include <glib.h>
-#include "pk-backend.h"
+#include "../pk-backend.h"
 #include "pkg.h"
 
-#include "query.h"		/* Prototypes */
 
-#include "db.h"			/* db_open_remote */
-#include "hash_traverse.h"	/* HASH_FOR */
-#include "utils.h"		/* string_match */
-#include "pkgutils.h"		/* pkgutils_... */
+#include "../db.h"		/* db_open_remote */
+#include "../hash_traverse.h"	/* HASH_FOR */
+#include "../utils.h"		/* string_match */
+#include "../pkgutils.h"	/* pkgutils_... */
+#include "core.h"		/* Prototypes */
+
+enum repo_type {
+	REPO_INVALID,
+	REPO_ANY,
+	REPO_LOCAL,
+	REPO_REMOTE
+};
 
-struct query {
-	int		load_flags;
+struct query_unpacked_source {
+	gboolean	skip_id_match;
 	const gchar    *name;
 	const gchar    *version;
 	const gchar    *arch;
 	const gchar    *data;
 	gchar         **strv;
+};
+
+struct query {
 	PkBackend      *backend;
 	struct pkgdb   *db;
 
-	gboolean	any_repo;
-	gboolean	local_repo;
+	struct query_unpacked_source *su;
 
+	enum repo_type	rtype;
+
+	struct query_source *s;
 	struct query_target *t;
 };
 
-static gboolean match_id_in_it(struct pkgdb_it *it, struct query *q, struct pkg
-**match_pkg_p, gchar **match_id_p);
-static gboolean	try_id_match(struct pkg *pkg, struct query *q, gchar **match_id);
+static enum repo_type type_of_repo_name(const char *name);
+static gboolean	can_remote_iterate(struct query *q);
+static gchar   *match_pkg(struct pkg *pkg, struct query *q);
 static int	jobs_add_pkg(struct pkg_jobs *jobs, match_t type, struct pkg *pkg);
 static int	jobs_repo_from_query(struct pkg_jobs *jobs, struct query *q);
-static void	query_free_contents(struct query *q);
+static struct pkg *match_iterator(struct pkgdb_it *it, struct query *q, gchar **match_id_p);
+static struct query_unpacked_source *init_unpacked_source(PkBackend *backend, struct query_source *s);
+static void	free_unpacked_source(struct query_unpacked_source **su_p);
 
 /* Returns the backend stored inside the struct query. */
 PkBackend      *
@@ -77,28 +91,24 @@
 	PkBitfield	filters;
 	const char     *name;
 	gchar          *match_id;
-	struct pkg     *match_pkg;
+	struct pkg     *pkg;
 	struct pkgdb   *db;
 	struct pkgdb_it *it;
 
 	success = FALSE;
 	match = MATCH_EXACT;
 	match_id = NULL;
-	match_pkg = NULL;
+	pkg = NULL;
 	db = q->db;
-	name = q->name;
+	name = q->su->name;
 
 	/*
 	 * If we're not given a specific repository in the PackageID, we want
 	 * to try searching locally first and then remotely; otherwise which
 	 * database we query depends on the repository we have been given.
 	 */
-	if (q->any_repo == TRUE)
-		try_local = try_remote = TRUE;
-	else {
-		try_local = (q->local_repo == TRUE);
-		try_remote = (q->local_repo == FALSE);
-	}
+	try_local = (q->rtype != REPO_REMOTE);
+	try_remote = (q->rtype != REPO_LOCAL);
 
 	/* Apply filters, if any */
 	filters = pk_backend_get_uint(q->backend, "filters");
@@ -110,110 +120,33 @@
 	/* Try a local search first, if applicable. */
 	it = (try_local ? pkgdb_query(db, name, match) : NULL);
 	if (it != NULL)
-		success = match_id_in_it(it, q, &match_pkg, &match_id);
+		pkg = match_iterator(it, q, &match_id);
 	pkgdb_it_free(it);
 
-	if (success == TRUE)
+	/* No point trying remote if we got a local match */
+	if (pkg != NULL)
 		try_remote = FALSE;
 
 	/* Next, try a remote search, again only if applicable. */
-	it = (try_remote ? pkgdb_rquery(db, name, match, q->data) : NULL);
-	if (it != NULL)
-		success = match_id_in_it(it, q, &match_pkg, &match_id);
+	it = (try_remote ? pkgdb_rquery(db, name, match, q->su->data) : NULL);
+	if (it != NULL && can_remote_iterate(q))
+		pkg = match_iterator(it, q, &match_id);
 	pkgdb_it_free(it);
 
-	/*
-	 * Assume any error is due to not finding packages. At time of
-	 * writing this is true, but may change.
-	 */
-	if (success == TRUE) {
-		if (q->t->type == QUERY_EMIT)
-			q->t->data.emit.f(match_pkg, match_id, q);
-		else if (q->t->type == QUERY_JOB)
-			query_emit_to_job(match_pkg, match_id, q);
-	} else
+	if (pkg == NULL)
 		pk_backend_error_code(q->backend,
 		    PK_ERROR_ENUM_PACKAGE_NOT_FOUND,
 		    "package not found");
-
-	pkg_free(match_pkg);
-	g_free(match_id);
-
-	return success;
-}
-
-/*
- * Iterates a query function over all PackageIDs provided for this job.
- * 
- * This provides each iterating function call with a query structure ready to
- * run and updates the percentage after each iteration.
- * 
- * It also *finishes* the backend job.
- */
-gboolean
-query_do(PkBackend *backend, struct query_target *t, query_body_ptr body)
-{
-	gboolean	no_error_yet;
-	guint		i;
-	guint		len;
-	struct pkgdb   *db;
-	struct query   *q;
-	gchar         **package_ids;
-
-	(void)pk_backend_set_percentage(backend,
-	    PK_BACKEND_PERCENTAGE_INVALID);
-
-	/*
-	 * We're using length/index instead of incrementing the pointer to NULL
-	 * so that we can infer the progress bar percentage.
-	 */
-	package_ids = pk_backend_get_strv(backend, "package_ids");
-	len = g_strv_length(package_ids);
-
-	db = NULL;
-	q = NULL;
-
-	no_error_yet = db_open_remote(&db, backend);
-
-	pk_backend_set_percentage(backend, 0);
-	for (i = 0; i < len && no_error_yet; i++) {
-		no_error_yet = query_do_single(package_ids[i],
-		    backend,
-		    db,
-		    t,
-		    body);
-		pk_backend_set_percentage(backend, ((i * 100) / len));
+	else {
+		if (q->t->type == QUERY_EMIT)
+			success = q->t->data.emit.f(pkg, match_id, q);
+		else if (q->t->type == QUERY_JOB)
+			success = query_emit_to_job(pkg, match_id, q);
 	}
 
-	pkgdb_close(db);
-
-	pk_backend_finished(backend);
-
-	return no_error_yet;
-}
-
-/*
- * Runs a query over one PackageID.
- * 
- * This provides the emitting function with a query structure ready to run, but
- * does not do any backend housekeeping.
- */
-gboolean
-query_do_single(gchar *package_id,
-    PkBackend *backend,
-    struct pkgdb *db,
-    struct query_target *t,
-    query_body_ptr body)
-{
-	gboolean success;
-	struct query *q;
-
-	q = NULL;
-	success = query_init(package_id, backend, db, t, &q);
-	if (success)
-	    success = body(q);
+	pkg_free(pkg);
+	g_free(match_id);
 
-	query_free(q);
 	return success;
 }
 
@@ -262,145 +195,193 @@
 	return success;
 }
 
+/*
+ * Runs an assembled query.
+ */
+gboolean
+query_run(struct query *q)
+{
 
+	return q->s->body(q);
+}
 
-/* Creates a struct query for the given backend and target ID. */
-gboolean
-query_init(const gchar *id,
-    PkBackend *backend,
+/*
+ * Creates a struct query for the given backend, database, source and target.
+ * 
+ * Usually you'll want to use "query_do" instead of calling this directly.
+ */
+struct query   *
+query_init(PkBackend *backend,
     struct pkgdb *db,
-    struct query_target *t,
-    struct query **q_p)
+    struct query_source *s,
+    struct query_target *t)
 {
 	gboolean	success;
 	struct query   *q;
 
-	q = *q_p;
-	if (q == NULL)
-		q = g_new0(struct query, 1);
-	else
-		query_free_contents(q);
+	success = FALSE;
 
+	q = calloc(1, sizeof(struct query));
+	if (q == NULL) {
+		ERR(backend, PK_ERROR_ENUM_OOM, "couldn't allocate query");
+		goto cleanup;
+	}
 	q->backend = backend;
 	q->db = db;
+	q->s = s;
 	q->t = t;
 
-	success = split_id(id,
-	    &(q->strv),
-	    &(q->name),
-	    &(q->version),
-	    &(q->arch),
-	    &(q->data));
-	if (success == FALSE) {
-		pk_backend_error_code(backend,
-		    PK_ERROR_ENUM_PACKAGE_ID_INVALID,
-		    "invalid package id");
+	q->su = init_unpacked_source(backend, s);
+	if (q->su == NULL)
 		goto cleanup;
-	}
-	/*
-	 * Check the repository to make sure it's sane, and populate the repo
-	 * type flags in the state for later consumption.
-	 */
-	if (q->data == NULL)
-		q->any_repo = TRUE;
-	else if (strcmp(q->data, "installed") == 0)
-		q->local_repo = TRUE;
-	else if (pkg_repo_find_ident(q->data) == NULL) {
-		pk_backend_error_code(backend,
-		    PK_ERROR_ENUM_REPO_NOT_FOUND,
-		    "no such repository");
-		success = FALSE;
+
+	q->rtype = type_of_repo_name(q->su->data);
+	if (q->rtype == REPO_INVALID) {
+		ERR(backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "no such repo");
 		goto cleanup;
 	}
-	/*
-	 * Stop pkg from catching fire if we try to load files from
-	 * non-installed packages.
-	 */
-	if (q->t->type == QUERY_EMIT) {
-		gboolean	loading_files;
+	success = TRUE;
 
-		loading_files = (q->t->data.emit.load_flags &
-		    PKG_LOAD_FILES) ? TRUE : FALSE;
-		if (q->local_repo == FALSE && loading_files) {
-			pk_backend_error_code(backend,
-			    PK_ERROR_ENUM_CANNOT_GET_FILELIST,
-			    "cannot get files for remote package");
-			success = FALSE;
-			goto cleanup;
-		}
-	}
 cleanup:
-	if (success == FALSE) {
-		query_free(q);
-		q = NULL;
-	}
-	*q_p = q;
-	return success;
+	if (success == FALSE)
+		query_free(&q);
+
+	return q;
 }
 
 /* Deallocates a struct query and any contents it owns. */
 void
-query_free(struct query *q)
+query_free(struct query **q_p)
 {
+	struct query   *q;
+
+	q = (q_p == NULL ? NULL : *q_p);
 
 	if (q != NULL) {
-		query_free_contents(q);
-		g_free(q);
+		/*
+		 * The database, source and target structures are owned by
+		 * the creator and not freed here.
+		 */
+
+		if (q->su != NULL)
+			free_unpacked_source(&(q->su));
+
+		free(q);
+		*q_p = NULL;
 	}
 }
 
-static gboolean
-match_id_in_it(struct pkgdb_it *it,
-    struct query *q,
-    struct pkg **match_pkg_p,
-    gchar **match_id_p)
+/*
+ * Updates the PackageKit percentage to reflect progress on this query. If
+ * this query is part of a subquery, then the percentage will be scaled
+ * appropriately.
+ */
+void
+query_set_percentage(struct query *q, unsigned char percent)
 {
-	int		err;
-	int		load_flags;
+	guint		scaled_percent;
 
-	/* TODO: Filters */
+	if (percent == PK_BACKEND_PERCENTAGE_INVALID)
+		scaled_percent = PK_BACKEND_PERCENTAGE_INVALID;
+	else {
+		if (percent > 100)
+			percent = 100;
 
-	*match_pkg_p = NULL;
-	*match_id_p = NULL;
+		scaled_percent = (((100 * q->s->position) +
+		    (percent * (q->s->position + 1))) / (q->s->total));
+	}
 
-	if (q->t->type == QUERY_EMIT)
-		load_flags = q->t->data.emit.load_flags;
-	else
-		load_flags = PKG_LOAD_BASIC;
+	(void)pk_backend_set_percentage(q->backend, scaled_percent);
+}
 
-	for (HASH_FOR(err, pkgdb_it_next, it, match_pkg_p, load_flags))
-		if (try_id_match(*match_pkg_p, q, match_id_p) == TRUE)
-			break;
+/* Finds the type of the given PackageKit repository name. */
+static enum repo_type
+type_of_repo_name(const char *name)
+{
+	enum repo_type	rtype;
+
+	if (name == NULL)
+		rtype = REPO_ANY;
+	else if (strcmp(name, "installed") == 0)
+		rtype = REPO_LOCAL;
+	else if (pkg_repo_find_ident(name) != NULL)
+		rtype = REPO_REMOTE;
+	else
+		rtype = REPO_INVALID;
 
-	return (err == EPKG_OK && *match_id_p != NULL) ? TRUE : FALSE;
+	return rtype;
 }
 
+/*
+ * Checks to see if trying to do a remote package iteration with this query
+ * could spell disaster.
+ */
 static gboolean
-try_id_match(struct pkg *pkg, struct query *q, char **match_id)
+can_remote_iterate(struct query *q)
+{
+	gboolean	sane;
+
+	/* Innocent until proven guilty */
+	sane = TRUE;
+
+	/*
+	 * Stop pkg from catching fire if we try to load files from
+	 * non-installed packages.
+	 */
+	if (q->t->type == QUERY_EMIT) {
+		int		loading_files;
+
+		loading_files = (q->t->data.emit.load_flags & PKG_LOAD_FILES);
+		if (loading_files) {
+			ERR(q->backend,
+			    PK_ERROR_ENUM_CANNOT_GET_FILELIST,
+			    "cannot get files for remote package");
+			sane = FALSE;
+		}
+	}
+	return sane;
+}
+
+/*
+ * Checks whether a candidate package matches any constraints provided by the
+ * query and, if so, returns its full PackageID; otherwise NULL.
+ */
+static gchar   *
+match_pkg(struct pkg *pkg, struct query *q)
 {
 	gboolean	matches;
 	int		i;
+	gchar          *match_id;
 	const gchar   **pkg_id_bits;
 
 	pkg_id_bits = g_new0(const gchar *, 4);
 
-	g_free(*match_id);
-	*match_id = pkgutils_pkg_to_id_through(pkg, pkg_id_bits);
+	match_id = pkgutils_pkg_to_id_through(pkg, pkg_id_bits);
 
-	/*
-	 * Succeed if this package's PackageID fields match the original
-	 * PackageID.  Of course, the original ID might have missing fields
-	 * (NULLs), so we treat a comparison involving one as a success. This
-	 * means using our "weak strcmp" instead of normal strcmp or even
-	 * g_strcmp0.
-	 */
-	for (matches = TRUE, i = PK_PACKAGE_ID_NAME;
-	    matches == TRUE && i <= PK_PACKAGE_ID_DATA;
-	    i++)
-		matches = string_match((q->strv)[i], pkg_id_bits[i]);
+	if (q->su->skip_id_match == TRUE)
+		matches = TRUE;
+	else {
+		/*
+		 * Succeed if this package's PackageID fields match the
+		 * original PackageID.  Of course, the original ID might have
+		 * missing fields (NULLs), so we treat a comparison involving
+		 * one as a success. This means using our "weak strcmp"
+		 * instead of normal strcmp or even g_strcmp0.
+		 */
+		for (matches = TRUE, i = PK_PACKAGE_ID_NAME;
+		    matches == TRUE && i <= PK_PACKAGE_ID_DATA;
+		    i++)
+			matches = string_match((q->su->strv)[i],
+			    pkg_id_bits[i]);
+	}
 
 	g_free(pkg_id_bits);
-	return matches;
+
+	if (matches == FALSE) {
+		g_free(match_id);
+		match_id = NULL;
+	}
+	return match_id;
 }
 
 /* Adds a single package to a jobs structure. */
@@ -420,21 +401,109 @@
 {
 	int		err;
 
-	if (q->data == NULL)
+	if (q->su->data == NULL)
 		err = EPKG_OK;
 	else
-		err = pkg_jobs_set_repository(jobs, q->data);
+		err = pkg_jobs_set_repository(jobs, q->su->data);
 
 	return err;
 }
 
-/* Frees the owned contents of a struct query, but not the struct itself. */
+/*
+ * Tries to find a query-matching package in a database iterator. Returns the
+ * package if one matches, or NULL; if match_id_p is non-null, its full
+ * PackageID will be emitted there.
+ */
+static struct pkg *
+match_iterator(struct pkgdb_it *it, struct query *q, gchar **match_id_p)
+{
+	int		load_flags;
+	gchar          *match_id;
+	struct pkg     *pkg;
+
+	if (q->t->type == QUERY_EMIT)
+		load_flags = q->t->data.emit.load_flags;
+	else
+		load_flags = PKG_LOAD_BASIC;
+
+	match_id = NULL;
+	pkg = NULL;
+	while (pkgdb_it_next(it, &pkg, load_flags) == EPKG_OK) {
+		match_id = match_pkg(pkg, q);
+		/* Did it match? */
+		if (match_id != NULL)
+			break;
+	}
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307081155.r68BtLlK042448>