From owner-svn-soc-all@FreeBSD.ORG Fri Aug 9 09:42:17 2013 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id E8557789 for ; Fri, 9 Aug 2013 09:42:17 +0000 (UTC) (envelope-from mattbw@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id D3F862AED for ; Fri, 9 Aug 2013 09:42:17 +0000 (UTC) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.14.7/8.14.7) with ESMTP id r799gHVj028216 for ; Fri, 9 Aug 2013 09:42:17 GMT (envelope-from mattbw@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.14.7/8.14.6/Submit) id r799gHk6028209 for svn-soc-all@FreeBSD.org; Fri, 9 Aug 2013 09:42:17 GMT (envelope-from mattbw@FreeBSD.org) Date: Fri, 9 Aug 2013 09:42:17 GMT Message-Id: <201308090942.r799gHk6028209@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to mattbw@FreeBSD.org using -f From: mattbw@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r255723 - in soc2013/mattbw/backend: . jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Aug 2013 09:42:18 -0000 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 /* 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 + * + * 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 /* 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 + * + * 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 */ +#include /* gchar, g_... */ +#include /* 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 + * + * 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 /* 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 */