Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 Aug 2013 09:42:17 GMT
From:      mattbw@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r255723 - in soc2013/mattbw/backend: . jobs
Message-ID:  <201308090942.r799gHk6028209@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mattbw
Date: Fri Aug  9 09:42:17 2013
New Revision: 255723
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=255723

Log:
  More refactoring of jobs, flesh out apply error messages.
  
  Jobs are now split into check/core/do, where check contains the job checking
  logic, do contains the high-level specification-based functions, and core
  contains thin wrappers and glue over the pkgng functions.
  
  I need to check the output of pkg_jobs_apply to see which error messages are
  actually in use, but theoretically this should make things slightly easier
  to see on the developer level at least.
  
  All that remains is to move jobs.c to jobs/core.c and do some more tidying
  up and separating.
  

Added:
  soc2013/mattbw/backend/jobs/core.h
  soc2013/mattbw/backend/jobs/do.c
  soc2013/mattbw/backend/jobs/do.h
Modified:
  soc2013/mattbw/backend/Makefile
  soc2013/mattbw/backend/jobs.c
  soc2013/mattbw/backend/jobs.h

Modified: soc2013/mattbw/backend/Makefile
==============================================================================
--- soc2013/mattbw/backend/Makefile	Fri Aug  9 08:40:31 2013	(r255722)
+++ soc2013/mattbw/backend/Makefile	Fri Aug  9 09:42:17 2013	(r255723)
@@ -54,7 +54,8 @@
 		query/match.c
 
 SRCS+=						\
-		jobs/check.c	
+		jobs/check.c			\
+		jobs/do.c
 
 LIBDIR=		/usr/local/lib/packagekit-backend
 

Modified: soc2013/mattbw/backend/jobs.c
==============================================================================
--- soc2013/mattbw/backend/jobs.c	Fri Aug  9 08:40:31 2013	(r255722)
+++ soc2013/mattbw/backend/jobs.c	Fri Aug  9 09:42:17 2013	(r255723)
@@ -34,175 +34,67 @@
 #include "jobs/check.h"		/* jobs_check_... */
 #include "pkgutils.h"		/* pkgutils_... */
 
-
-static bool jobs_do_apply(const struct jobs_spec *spec, struct pkg_jobs *jobs);
-static bool jobs_do_check(const struct jobs_spec *spec, struct pkg_jobs *jobs, gchar **package_ids, guint count);
-static bool jobs_do_multiple_repos(struct pkgdb *db, const struct jobs_spec *spec, gchar **package_ids, guint count);
-static bool jobs_do_same_repo(struct pkgdb *db, const struct jobs_spec *spec, gchar **package_ids, guint count, const char *reponame);
-static bool jobs_do_set_repo(const struct jobs_spec *spec, struct pkg_jobs *jobs, const char *reponame);
-static bool jobs_do_solve(const struct jobs_spec *spec, struct pkg_jobs *jobs);
-static char **jobs_do_populate(const struct jobs_spec *spec, struct pkg_jobs *jobs, gchar **package_ids, guint count);
 static char **namevers_from_package_ids(gchar **package_ids, guint count);
-static struct pkg_jobs *jobs_do_allocate(const struct jobs_spec *spec, struct pkgdb *db);
-static struct pkg_jobs *jobs_do_initialise(const struct jobs_spec *spec, struct pkgdb *db, const char *reponame);
-static void free_namevers(char ***namevers_p, guint count);
-static void jobs_free(struct pkg_jobs **jobs_p);
+
+static const char *APPLY_ERRORS[] = {
+	"This shouldn't occur and is a bug.",	/* EPKG_OK */
+	"This shouldn't occur and is a bug.",	/* EPKG_END */
+	"This shouldn't occur and is a bug.",	/* EPKG_WARN */
+	"Fatal error.",				/* EPKG_FATAL */
+	"Package required by another package.",	/* EPKG_REQUIRED */
+	"Already installed.",			/* EPKG_INSTALLED */
+	"Unresolved dependencies.",		/* EPKG_DEPENDENCY */
+	"A package is currently locked.",	/* EPKG_LOCKED */
+	"No usable database available.",	/* EPKG_ENODB */
+	"Local file newer than remote file.",	/* EPKG_UPTODATE */
+	"Unknown keyword.",			/* EPKG_UNKNOWN */
+	"Incompatible repo schema version",	/* EPKG_REPOSCHEMA */
+	"Insufficient privilege for action.",	/* EPKG_ENOACCESS */
+	"Insecure privileges on DB file."	/* EPKG_INSECURE */
+};
 
 /* Applies a job with the given error enums and the standard event callback. */
 bool
-jobs_apply(struct pkg_jobs *jobs, PkBackend *backend,
-    PkErrorEnum no_jobs, PkErrorEnum job_failed)
+jobs_apply(struct pkg_jobs *jobs, PkBackend *backend, PkErrorEnum job_failed)
 {
-	bool success;
+	int		err;
 
-	success = false;
 	assert(backend != NULL);
 
 	pkg_event_register(event_cb, backend);
-
-	if (pkg_jobs_count(jobs) == 0)
-		ERR(backend, no_jobs, "nothing to do");
-	else if (pkg_jobs_apply(jobs) != EPKG_OK)
-		ERR(backend, job_failed, "job failed");
-	else
-		success = true;
-
-	pkg_event_register(NULL, NULL);
-
-	return success;
-}
-
-
-
-/* Performs a job from a job specification. */
-bool
-jobs_do(const struct jobs_spec *spec)
-{
-	bool		success;
-	unsigned int	count;
-	struct pkgdb   *db;
-	gchar	      **package_ids;
-
-	assert(spec != NULL);
-	assert(spec->backend != NULL);
-	assert(spec->info != NULL);
-
-	success = false;
-
-	package_ids = NULL;
-	if (spec->use_package_ids) {
-		package_ids = pk_backend_get_strv(spec->backend, "package_ids");
+	{
+		err = pkg_jobs_apply(jobs);
 	}
+	pkg_event_register(NULL, NULL);
 
-	count = 0;
-	if (package_ids != NULL) {
-		count = g_strv_length(package_ids);
-	}
-
-	db = db_open_remote(spec->backend);
-	if (db != NULL) {
-		if (package_ids == NULL) {
-			success = jobs_do_same_repo(db, spec, NULL, 0, "");
-		} else {
-			success = jobs_do_multiple_repos(db, spec, package_ids,
-			    count);
-		}
-
-		pkgdb_close(db);
+	assert(EPKG_OK <= err);
+	assert(err <= EPKG_INSECURE);
+	if (err != EPKG_OK) {
+		ERR(backend, job_failed, APPLY_ERRORS[err]);
 	}
 
-	return success;
+	return (err == EPKG_OK);
 }
 
-
-
-/*
- * Performs a job on a batch of PackageIDs whose repos may be different.
- */
-static bool
-jobs_do_multiple_repos(struct pkgdb *db, const struct jobs_spec *spec,
-    gchar **package_ids, guint count)
+bool
+jobs_set_repo(struct pkg_jobs *jobs, const char *reponame)
 {
+	bool		is_remote;
 	bool		success;
-	unsigned int	i;
-	char	       *repo;
-	gchar	      **splits;
 
- 	/*
-	 * HACK ALERT
-	 *
-	 * We'd ideally like to do one job for all PackageIDs but, because
-	 * there could be more than one repo being used (as each PackageID has
-	 * its own repo), we need to do one job per PackageID.
-	 * TODO: consider bundling PackageIDs up into separate jobs per repo?
-	 */
 	success = true;
-	for (i = 0; i < count; i++) {
-		if (!success)
-			break;
-
-		/* Nastily inefficient */
-		splits = pk_package_id_split(package_ids[i]);
-		if (splits == NULL)
-			repo = strdup("");
-		else
-			repo = strdup(splits[PK_PACKAGE_ID_DATA]);
-		g_strfreev(splits);
-
-		success = jobs_do_same_repo(db, spec, package_ids + i,
-		    1, repo);
-		free(repo);
-	}
-
-	return success;
-}
-
-/*
- * Performs a job on a certain batch of PackageIDs, each with the same repo.
- * count can be 0, in which case no PackageIDs are used.
- */
-static bool
-jobs_do_same_repo(struct pkgdb *db, const struct jobs_spec *spec,
-    gchar **package_ids, guint count, const char *reponame)
-{
-	bool		success;
-	struct pkg_jobs *jobs;
-
-	assert(db != NULL);
-	assert(spec != NULL);
-	assert(package_ids != NULL || 0 == count);
-	assert(package_ids == NULL || 0 < count);
-
-	success = false;
-
-	jobs = jobs_do_initialise(spec, db, reponame);
-	if (jobs != NULL) {
-		bool		populated;
-		bool		solved;
-		bool		valid;
-		char	      **namevers;
 
-		solved = valid = false;
-
-		namevers = jobs_do_populate(spec, jobs, package_ids, count);
-		populated = (package_ids == NULL || namevers != NULL);
-
-		if (populated) {
-			solved = jobs_do_solve(spec, jobs);
-		}
-
-		if (populated && solved) {
-			valid = jobs_do_check(spec, jobs, package_ids, count);
-		}
+	is_remote = (reponame != NULL && strcmp(reponame, "installed") != 0);
 
-		if (populated && solved && valid) {
-			success = jobs_do_apply(spec, jobs);
-		}
+	if (is_remote) {
+		int		err;
 
-		pkg_jobs_free(jobs);
-		free_namevers(&namevers, count);
+		err = pkg_jobs_set_repository(jobs, reponame);
+		success = (err == EPKG_OK);
 	}
 
+	assert(is_remote || success == true);
+
 	return success;
 }
 
@@ -220,15 +112,15 @@
 
 	namevers = NULL;
 
-	count = g_strv_length(package_ids);
 	if (count > 0) {
 		int		err;
 
 		namevers = namevers_from_package_ids(package_ids, count);
 
 		err = pkg_jobs_add(jobs, MATCH_EXACT, namevers, (int)count);
-		if (err != EPKG_OK)
-			free_namevers(&namevers, count);
+		if (err != EPKG_OK) {
+			jobs_free_namevers(&namevers, count);
+		}
 	}
 
 	return namevers;
@@ -252,178 +144,40 @@
  	}
 }
 
-static bool
-jobs_do_apply(const struct jobs_spec *spec, struct pkg_jobs *jobs)
-{
-	bool success;
-
-	assert(spec != NULL);
-	assert(jobs != NULL);
-
-	STATUS(spec->backend, spec->status);
-
-	if (spec->simulate) {
-		success = true;
-		jobs_emit_packages(jobs, spec->backend, spec->info);
-	} else {
-		success = jobs_apply(jobs, spec->backend,
-		    spec->no_jobs_error,
-		    spec->jobs_failed_error);
-	}
-
-	return success;
-}
-
-static bool
-jobs_do_check(const struct jobs_spec *spec, struct pkg_jobs *jobs,
-    gchar **package_ids, guint count)
-{
-	bool		success;
-
-	assert(spec != NULL);
-	assert(jobs != NULL);
-	assert(package_ids != NULL || 0 == count);
-	assert(package_ids == NULL || 0 < count);
-
-	success = true;
-
-	if (package_ids != NULL) {
-		success = jobs_check_package_ids(jobs, package_ids, count,
-		    spec->reject_non_updates);
-	}
-	if (!success) {
-		ERR(spec->backend,
-		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
-		    "packages failed suitability check");
-	}
-
-	assert(0 < count || success);
-
-	return success;
-}
-
-static bool
-jobs_do_set_repo(const struct jobs_spec *spec, struct pkg_jobs *jobs,
-    const char *reponame)
+void
+jobs_free_namevers(char ***namevers_p, guint count)
 {
-	bool		is_remote;
-	bool		success;
-
-	assert(spec != NULL);
-	assert(jobs != NULL);
-	/* reponame can be NULL */
-
-	success = true;
-
-	is_remote = (reponame != NULL && strcmp(reponame, "installed") != 0);
-
-	if (is_remote) {
-		int		err;
-
-		err = pkg_jobs_set_repository(jobs, reponame);
-		if (err != EPKG_OK) {
-			char	       *err_message;
+	unsigned int		i;
 
-			(void)asprintf(&err_message,
-			    "Could not set job repository to '%s'.",
-			    reponame);
-	 		ERR(spec->backend,
-			    PK_ERROR_ENUM_REPO_NOT_FOUND,
-			    err_message);
-	 		free(err_message);
+	assert(namevers_p != NULL);
 
-	 		success = false;
-	 	}
+	if (*namevers_p != NULL) {
+		for (i = 0; i < count; i++)
+			free(*namevers_p[i]);
+		free(*namevers_p);
+		*namevers_p = NULL;
 	}
-
-	assert(is_remote || success == true);
-
-	return success;
 }
 
-static bool
-jobs_do_solve(const struct jobs_spec *spec, struct pkg_jobs *jobs)
+/* Overly safe wrapper around pkg_jobs_new. */
+struct pkg_jobs *
+jobs_allocate(pkg_jobs_t type, struct pkgdb *db)
 {
-	bool		solved;
 	int		err;
-
-	err = pkg_jobs_solve(jobs);
-	if (err == EPKG_OK) {
-		solved = true;
-	} else {
-		solved = false;
-		ERR(spec->backend,
-		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
-		    "could not solve the job");
-	}	
-
-	return solved;
-}
-
-static char **
-jobs_do_populate(const struct jobs_spec *spec, struct pkg_jobs *jobs,
-    gchar **package_ids, guint count)
-{
-	char	      **namevers;
-
-	assert(spec != NULL);
-	assert(jobs != NULL);
-	assert(package_ids != NULL || count == 0);
-	assert(package_ids == NULL || count >= 1);
-
-	namevers = NULL;
-	if (package_ids != NULL) {
-		STATUS(spec->backend, PK_STATUS_ENUM_DEP_RESOLVE);
-
-		namevers = jobs_add_package_ids(jobs, package_ids, count);
-		if (namevers == NULL) {
-			ERR(spec->backend,
-			    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
-			    "could not find all requested packages");
-		}
-	}
-
-	assert(count >= 1 || namevers == NULL);
-
-	return namevers;
-}
-
-static struct pkg_jobs *
-jobs_do_initialise(const struct jobs_spec *spec, struct pkgdb *db,
-    const char *reponame)
-{
 	struct pkg_jobs *jobs;
 
-	assert(spec != NULL);
 	assert(db != NULL);
-	/* reponame may be NULL */
 
-	jobs = jobs_do_allocate(spec, db);
-	if (jobs != NULL) {
-		bool		repo_success;
-
-		repo_success = jobs_do_set_repo(spec, jobs, reponame);
-		if (!repo_success) {
-			jobs_free(&jobs);
-		}
+	jobs = NULL;
+	err = pkg_jobs_new(&jobs, type, db);
+	if (err != EPKG_OK && jobs != NULL) {
+		jobs_free(&jobs);
 	}
 
-	return jobs;
-}
-
-static void
-free_namevers(char ***namevers_p, guint count)
-{
-	unsigned int		i;
-
-	assert(namevers_p != NULL);
+	assert(err == EPKG_OK || jobs == NULL);
+	assert(err != EPKG_OK || jobs != NULL);
 
-	if (*namevers_p != NULL) {
-		for (i = 0; i < count; i++)
-			free(*namevers_p[i]);
-		free(*namevers_p);
-		*namevers_p = NULL;
-	}
+	return jobs;
 }
 
 /* Overly safe wrapper around pkg_jobs_free. */
@@ -432,7 +186,7 @@
 {
 
 	assert(jobs_p != NULL);
-	free(*jobs_p);
+	pkg_jobs_free(*jobs_p);
 	*jobs_p = NULL;
 }
 
@@ -448,7 +202,7 @@
 			namevers[i] = pkgutils_package_id_namever(
 			    package_ids[i]);
 			if (namevers[i] == NULL) {
-				free_namevers(&namevers, count);
+				jobs_free_namevers(&namevers, count);
 				break;
 			}
 		}
@@ -457,26 +211,4 @@
 	return namevers;
 }
 
-/* Safe and noisy wrapper around pkg_jobs_new. */
-static struct pkg_jobs *
-jobs_do_allocate(const struct jobs_spec *spec, struct pkgdb *db)
-{
-	int		err;
-	struct pkg_jobs *jobs;
-
-	assert(spec != NULL);
-	assert(db != NULL);
 
-	jobs = NULL;
-	err = pkg_jobs_new(&jobs, spec->type, db);
-	if (err != EPKG_OK) {
-		ERR(spec->backend,
-		    PK_ERROR_ENUM_INTERNAL_ERROR,
-		    "could not init pkg_jobs");
-	}
-
-	assert(err == EPKG_OK || jobs == NULL);
-	assert(err != EPKG_OK || jobs != NULL);
-
-	return jobs;
-}

Modified: soc2013/mattbw/backend/jobs.h
==============================================================================
--- soc2013/mattbw/backend/jobs.h	Fri Aug  9 08:40:31 2013	(r255722)
+++ soc2013/mattbw/backend/jobs.h	Fri Aug  9 09:42:17 2013	(r255723)
@@ -21,27 +21,10 @@
 #ifndef _PKGNG_BACKEND_JOBS_H_
 #define _PKGNG_BACKEND_JOBS_H_
 
-#include <stdbool.h>		/* bool */
-#include "pk-backend.h"		/* PkBackend */
-
-typedef		PkInfoEnum (*pkg_info_ptr) (struct pkg *pkg);
-
-struct jobs_spec {
-	pkg_jobs_t	type;
-	PkErrorEnum	jobs_failed_error;
-	PkErrorEnum	no_jobs_error;
-	PkStatusEnum	status;
-	PkBackend      *backend;
-	pkg_info_ptr	info;
-	bool		reject_non_updates;
-	bool		simulate;
-	bool		use_package_ids;
-	bool		ignore;			/* Alignment */
-};
-
-bool		jobs_apply(struct pkg_jobs *jobs, PkBackend *backend, PkErrorEnum no_jobs, PkErrorEnum jobs_failed);
-bool		jobs_do(const struct jobs_spec *spec);
-char	      **jobs_add_package_ids(struct pkg_jobs *jobs, gchar **package_ids, guint count);
-void		jobs_emit_packages(struct pkg_jobs *jobs, PkBackend *backend, pkg_info_ptr info);
+/*
+ * The high-level interface for jobs in jobs/do.h now.
+ * TODO: remove this file
+ */
+#include "jobs/do.h"
 
 #endif				/* !_PKGNG_BACKEND_JOBS_H_ */

Added: soc2013/mattbw/backend/jobs/core.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2013/mattbw/backend/jobs/core.h	Fri Aug  9 09:42:17 2013	(r255723)
@@ -0,0 +1,37 @@
+/*-
+ * 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_JOBS_CORE_H_
+#define _PKGNG_BACKEND_JOBS_CORE_H_
+
+#include <stdbool.h>		/* bool */
+#include "../pk-backend.h"	/* PkBackend */
+
+typedef		PkInfoEnum (*pkg_info_ptr) (struct pkg *pkg);
+
+bool		jobs_apply(struct pkg_jobs *jobs, PkBackend *backend, PkErrorEnum jobs_failed);
+bool		jobs_set_repo(struct pkg_jobs *jobs, const char *reponame);
+char	      **jobs_add_package_ids(struct pkg_jobs *jobs, gchar **package_ids, guint count);
+struct pkg_jobs *jobs_allocate(pkg_jobs_t type, struct pkgdb *db);
+void		jobs_emit_packages(struct pkg_jobs *jobs, PkBackend *backend, pkg_info_ptr info);
+void		jobs_free(struct pkg_jobs **jobs_p);
+void		jobs_free_namevers(char ***namevers_p, guint count);
+
+#endif				/* !_PKGNG_BACKEND_JOBS_CORE_H_ */

Added: soc2013/mattbw/backend/jobs/do.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2013/mattbw/backend/jobs/do.c	Fri Aug  9 09:42:17 2013	(r255723)
@@ -0,0 +1,350 @@
+/*-
+ * 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.
+ */
+
+/* Higher level helper code for adapting pkgng jobs to PackageKit actions. */
+
+#include <assert.h>		/* assert */
+#include <glib.h>		/* gchar, g_... */
+#include <string.h>		/* strcmp */
+#include "../pk-backend.h"	/* pk_..., Pk... */
+#include "pkg.h"		/* pkg_... */
+
+#include "../db.h"		/* db_... */
+#include "../utils.h"		/* get_package_ids */
+#include "check.h"		/* jobs_check_... */
+#include "core.h"		/* jobs_... */
+#include "do.h"			/* jobs_do_... */
+
+static bool jobs_do_apply(const struct jobs_spec *spec, struct pkg_jobs *jobs);
+static bool jobs_do_check(const struct jobs_spec *spec, struct pkg_jobs *jobs, gchar **package_ids, guint count);
+static bool jobs_do_count(const struct jobs_spec *spec, struct pkg_jobs *jobs);
+static bool jobs_do_multiple_repos(struct pkgdb *db, const struct jobs_spec *spec, gchar **package_ids, guint count);
+static bool jobs_do_same_repo(struct pkgdb *db, const struct jobs_spec *spec, gchar **package_ids, guint count, const char *reponame);
+static bool jobs_do_set_repo(const struct jobs_spec *spec, struct pkg_jobs *jobs, const char *reponame);
+static bool jobs_do_solve(const struct jobs_spec *spec, struct pkg_jobs *jobs);
+static char **jobs_do_populate(const struct jobs_spec *spec, struct pkg_jobs *jobs, gchar **package_ids, guint count);
+static struct pkg_jobs *jobs_do_allocate(const struct jobs_spec *spec, struct pkgdb *db);
+static struct pkg_jobs *jobs_do_initialise(const struct jobs_spec *spec, struct pkgdb *db, const char *reponame);
+
+/* Performs a job from a job specification. */
+bool
+jobs_do(const struct jobs_spec *spec)
+{
+	bool		success;
+
+	struct pkgdb   *db;
+
+
+	assert(spec != NULL);
+	assert(spec->backend != NULL);
+	assert(spec->info != NULL);
+
+	success = false;
+
+	db = db_open_remote(spec->backend);
+	if (db != NULL) {
+		if (spec->use_package_ids) {
+			guint		count;
+			gchar	      **package_ids;
+
+			package_ids = get_package_ids(spec->backend, &count);
+			assert(package_ids != NULL);
+
+			success = jobs_do_multiple_repos(db, spec, package_ids,
+			    count);
+		} else {
+			success = jobs_do_same_repo(db, spec, NULL, 0, "");
+		}
+
+		pkgdb_close(db);
+	}
+
+	return success;
+}
+
+static bool
+jobs_do_apply(const struct jobs_spec *spec, struct pkg_jobs *jobs)
+{
+	bool		success;
+
+	assert(spec != NULL);
+	assert(jobs != NULL);
+
+	STATUS(spec->backend, spec->status);
+
+	if (spec->simulate) {
+		success = true;
+		jobs_emit_packages(jobs, spec->backend, spec->info);
+	} else {
+		success = jobs_apply(jobs, spec->backend,
+		    spec->jobs_failed_error);
+	}
+
+	return success;
+}
+
+static bool
+jobs_do_check(const struct jobs_spec *spec, struct pkg_jobs *jobs,
+    gchar **package_ids, guint count)
+{
+	bool		success;
+
+	assert(spec != NULL);
+	assert(jobs != NULL);
+	assert(package_ids != NULL || 0 == count);
+	assert(package_ids == NULL || 0 < count);
+
+	success = true;
+
+	if (package_ids != NULL) {
+		success = jobs_check_package_ids(jobs, package_ids, count,
+		    spec->reject_non_updates);
+	}
+	if (!success) {
+		ERR(spec->backend,
+		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
+		    "packages failed suitability check");
+	}
+
+	assert(0 < count || success);
+
+	return success;
+}
+
+static bool
+jobs_do_count(const struct jobs_spec *spec, struct pkg_jobs *jobs)
+{
+	int		count;
+
+	assert(spec != NULL);
+	assert(jobs != NULL);
+
+	count = pkg_jobs_count(jobs);
+	if (count == 0) {
+		ERR(spec->backend, spec->no_jobs_error, "nothing to do");
+	}
+
+	return (0 < count);
+}
+
+/*
+ * Performs a job on a batch of PackageIDs whose repos may be different.
+ */
+static bool
+jobs_do_multiple_repos(struct pkgdb *db, const struct jobs_spec *spec,
+    gchar **package_ids, guint count)
+{
+	bool		success;
+	unsigned int	i;
+	char	       *repo;
+	gchar	      **splits;
+
+ 	/*
+	 * HACK ALERT
+	 *
+	 * We'd ideally like to do one job for all PackageIDs but, because
+	 * there could be more than one repo being used (as each PackageID has
+	 * its own repo), we need to do one job per PackageID.
+	 * TODO: consider bundling PackageIDs up into separate jobs per repo?
+	 */
+	success = true;
+	for (i = 0; i < count; i++) {
+		if (!success)
+			break;
+
+		/* Nastily inefficient */
+		splits = pk_package_id_split(package_ids[i]);
+		if (splits == NULL)
+			repo = strdup("");
+		else
+			repo = strdup(splits[PK_PACKAGE_ID_DATA]);
+		g_strfreev(splits);
+
+		success = jobs_do_same_repo(db, spec, package_ids + i,
+		    1, repo);
+		free(repo);
+	}
+
+	return success;
+}
+
+/*
+ * Performs a job on a certain batch of PackageIDs, each with the same repo.
+ * count can be 0, in which case no PackageIDs are used.
+ */
+static bool
+jobs_do_same_repo(struct pkgdb *db, const struct jobs_spec *spec,
+    gchar **package_ids, guint count, const char *reponame)
+{
+	bool		success;
+	struct pkg_jobs *jobs;
+
+	assert(db != NULL);
+	assert(spec != NULL);
+	assert(package_ids != NULL || 0 == count);
+	assert(package_ids == NULL || 0 < count);
+
+	success = false;
+
+	jobs = jobs_do_initialise(spec, db, reponame);
+	if (jobs != NULL) {
+		bool		has_actions;
+		bool		populated;
+		bool		solved;
+		bool		valid;
+		char	      **namevers;
+
+		solved = has_actions = valid = false;
+
+		namevers = jobs_do_populate(spec, jobs, package_ids, count);
+		populated = (package_ids == NULL || namevers != NULL);
+
+		if (populated) {
+			solved = jobs_do_solve(spec, jobs);
+		}
+		if (populated && solved) {
+			has_actions = jobs_do_count(spec, jobs);
+		}
+		if (populated && solved && has_actions) {
+			valid = jobs_do_check(spec, jobs, package_ids, count);
+		}
+		if (populated && solved && has_actions && valid) {
+			success = jobs_do_apply(spec, jobs);
+		}
+
+		pkg_jobs_free(jobs);
+		jobs_free_namevers(&namevers, count);
+	}
+
+	return success;
+}
+
+static bool
+jobs_do_set_repo(const struct jobs_spec *spec, struct pkg_jobs *jobs,
+    const char *reponame)
+{
+	bool		success;
+
+	assert(spec != NULL);
+	assert(jobs != NULL);
+	/* reponame can be NULL */
+
+	success = jobs_set_repo(jobs, reponame);
+	if (!success) {
+		char	       *err_message;
+
+		(void)asprintf(&err_message,
+		    "Could not set job repository to '%s'.",
+		    reponame);
+ 		ERR(spec->backend,
+		    PK_ERROR_ENUM_REPO_NOT_FOUND,
+		    err_message);
+ 		free(err_message);
+	}
+
+	return success;
+}
+
+static bool
+jobs_do_solve(const struct jobs_spec *spec, struct pkg_jobs *jobs)
+{
+	bool		solved;
+	int		err;
+
+	err = pkg_jobs_solve(jobs);
+	solved = (err == EPKG_OK);
+
+	if (!solved) {
+		ERR(spec->backend,
+		    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
+		    "could not solve the job");
+	}	
+
+	return solved;
+}
+
+static char **
+jobs_do_populate(const struct jobs_spec *spec, struct pkg_jobs *jobs,
+    gchar **package_ids, guint count)
+{
+	char	      **namevers;
+
+	assert(spec != NULL);
+	assert(jobs != NULL);
+	assert(package_ids != NULL || count == 0);
+	assert(package_ids == NULL || count >= 1);
+
+	namevers = NULL;
+	if (package_ids != NULL) {
+		STATUS(spec->backend, PK_STATUS_ENUM_DEP_RESOLVE);
+
+		namevers = jobs_add_package_ids(jobs, package_ids, count);
+		if (namevers == NULL) {
+			ERR(spec->backend,
+			    PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
+			    "could not find all requested packages");
+		}
+	}
+
+	assert(count >= 1 || namevers == NULL);
+
+	return namevers;
+}
+
+static struct pkg_jobs *
+jobs_do_allocate(const struct jobs_spec *spec, struct pkgdb *db)
+{
+	struct pkg_jobs *jobs;
+
+	assert(spec != NULL);
+	assert(db != NULL);
+
+	jobs = jobs_allocate(spec->type, db);
+	if (jobs == NULL) {
+		ERR(spec->backend,
+		    PK_ERROR_ENUM_INTERNAL_ERROR,
+		    "could not init pkg_jobs");
+	}
+
+	return jobs;
+}
+
+static struct pkg_jobs *
+jobs_do_initialise(const struct jobs_spec *spec, struct pkgdb *db,
+    const char *reponame)
+{
+	struct pkg_jobs *jobs;
+
+	assert(spec != NULL);
+	assert(db != NULL);
+	/* reponame may be NULL */
+
+	jobs = jobs_do_allocate(spec, db);
+	if (jobs != NULL) {
+		bool		repo_success;
+
+		repo_success = jobs_do_set_repo(spec, jobs, reponame);
+		if (!repo_success) {
+			jobs_free(&jobs);
+		}
+	}
+
+	return jobs;
+}

Added: soc2013/mattbw/backend/jobs/do.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2013/mattbw/backend/jobs/do.h	Fri Aug  9 09:42:17 2013	(r255723)
@@ -0,0 +1,43 @@
+/*-
+ * 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_JOBS_DO_H
+#define _PKGNG_BACKEND_JOBS_DO_H
+
+#include <stdbool.h>		/* bool */
+#include "../pk-backend.h"	/* PkBackend */
+#include "core.h"		/* pkg_info_ptr */
+
+struct jobs_spec {
+	pkg_jobs_t	type;
+	PkErrorEnum	jobs_failed_error;
+	PkErrorEnum	no_jobs_error;
+	PkStatusEnum	status;
+	PkBackend      *backend;
+	pkg_info_ptr	info;
+	bool		reject_non_updates;
+	bool		simulate;
+	bool		use_package_ids;
+	bool		ignore;			/* Alignment */
+};
+
+bool		jobs_do(const struct jobs_spec *spec);
+
+#endif				/* !_PKGNG_BACKEND_JOBS_DO_H */



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