summaryrefslogtreecommitdiffstats
path: root/needbuild.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--needbuild.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/needbuild.c b/needbuild.c
new file mode 100644
index 0000000..fa8801a
--- /dev/null
+++ b/needbuild.c
@@ -0,0 +1,303 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2009,2012,2013,2016 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "error.h"
+#include "atoms.h"
+#include "strlist.h"
+#include "chunks.h"
+#include "trackingt.h"
+#include "tracking.h"
+#include "globmatch.h"
+#include "package.h"
+#include "needbuild.h"
+
+/* list all source packages in a distribution that needs buildd action
+
+ For each source package check:
+ - if tracking is enabled and there is a .log or .changes file
+ for the given arch -> SKIP
+ - if there is a binary package for the given architecture -> SKIP
+ - if the package's Architecture field excludes this arch -> SKIP
+ - if the package's Binary field only lists existing ones
+ (i.e. architecture all) -> SKIP
+*/
+
+static retvalue tracked_source_needs_build(architecture_t architecture, const char *sourcename, const char *sourceversion, const char *dscfilename, const struct strlist *binary, const struct trackedpackage *tp, bool printarch) {
+ bool found_binary[binary->count];
+ const char *archstring = atoms_architectures[architecture];
+ size_t archstringlen= strlen(archstring);
+ int i;
+
+ memset(found_binary, 0, sizeof(bool)*binary->count);
+ for (i = 0 ; i < tp->filekeys.count ; i++) {
+ enum filetype ft = tp->filetypes[i];
+ const char *fk = tp->filekeys.values[i];
+
+ if (ft == ft_XTRA_DATA)
+ continue;
+ if (ft == ft_ALL_BINARY) {
+ int j;
+
+ if (architecture == architecture_all) {
+ /* found an _all.deb, nothing to do */
+ return RET_NOTHING;
+ }
+
+ /* determine which binary files are arch all
+ packages: */
+ for (j = 0 ; j < binary->count ; j++) {
+ const char *b = binary->values[j];
+ size_t l = strlen(b);
+
+ if (strncmp(fk, b, l) == 0 &&
+ fk[l] == '_')
+ found_binary[j] = true;
+ }
+ continue;
+ }
+ if (ft == ft_ARCH_BINARY) {
+ const char *a = strrchr(fk, '_');
+
+ if (a == NULL)
+ continue;
+ a++;
+ if (strncmp(a, archstring, archstringlen) != 0 ||
+ a[archstringlen] != '.')
+ continue;
+ /* found an .deb with this architecture,
+ so nothing is to be done */
+ return RET_NOTHING;
+ }
+ if (ft == ft_LOG || ft == ft_BUILDINFO || ft == ft_CHANGES) {
+ const char *a = strrchr(fk, '_');
+ const char *e;
+
+ if (a == NULL)
+ continue;
+ a++;
+ while ((e = strchr(a, '+')) != NULL) {
+ if ((size_t)(e-a) != archstringlen) {
+ a = e+1;
+ continue;
+ }
+ if (memcmp(a, archstring, archstringlen) != 0){
+ a = e+1;
+ continue;
+ }
+ /* found something for this architecture */
+ return RET_NOTHING;
+ }
+ e = strchr(a, '.');
+ if (e == NULL)
+ continue;
+ if ((size_t)(e-a) != archstringlen) {
+ a = e+1;
+ continue;
+ }
+ if (memcmp(a, archstring, archstringlen) != 0){
+ a = e+1;
+ continue;
+ }
+ /* found something for this architecture */
+ return RET_NOTHING;
+ }
+ }
+ /* nothing for this architecture was found, check if is has any binary
+ packages that are lacking: */
+ for (i = 0 ; i < binary->count ; i++) {
+ if (!found_binary[i]) {
+ if (printarch)
+ printf("%s %s %s %s\n",
+ sourcename, sourceversion,
+ dscfilename, archstring);
+ else
+ printf("%s %s %s\n",
+ sourcename, sourceversion,
+ dscfilename);
+ return RET_OK;
+ }
+ }
+ /* all things listed in Binary already exists, nothing to do: */
+ return RET_NOTHING;
+}
+
+struct needbuild_data { architecture_t architecture;
+ trackingdb tracks;
+ /*@null@*/ const char *glob;
+ bool printarch;
+};
+
+static retvalue check_source_needs_build(struct package *package, void *data) {
+ struct target *target = package->target;
+ struct needbuild_data *d = data;
+ struct strlist binary, architectures, filekeys;
+ const char *dscfilename = NULL;
+ int i;
+ retvalue r;
+
+ if (d->glob != NULL && !globmatch(package->name, d->glob))
+ return RET_NOTHING;
+
+ r = package_getversion(package);
+ if (!RET_IS_OK(r))
+ return r;
+ r = chunk_getwordlist(package->control, "Architecture", &architectures);
+ if (RET_IS_OK(r)) {
+ bool skip = true;
+ const char *req = atoms_architectures[d->architecture];
+ const char *hyphen, *os;
+ size_t osl;
+
+ hyphen = strchr(req, '-');
+ if (hyphen == NULL) {
+ os = "linux";
+ osl = 5;
+ } else {
+ os = req;
+ osl = hyphen - req;
+ }
+
+ for (i = 0 ; i < architectures.count ; i++) {
+ const char *a = architectures.values[i];
+
+ if (strcmp(a, req) == 0) {
+ skip = false;
+ break;
+ }
+ /* "all" is not part of "any" or "*-any" */
+ if (d->architecture == architecture_all)
+ continue;
+ if (strcmp(a, "any") == 0) {
+ skip = false;
+ break;
+ }
+
+ size_t al = strlen(a);
+
+ if (al < 4 || memcmp(a + al - 4, "-any", 4) != 0)
+ continue;
+
+ if (al == osl + 4 && memcmp(a, os, osl) == 0) {
+ skip = false;
+ break;
+ }
+ }
+ strlist_done(&architectures);
+ if (skip) {
+ return RET_NOTHING;
+ }
+ }
+ r = chunk_getwordlist(package->control, "Binary", &binary);
+ if (!RET_IS_OK(r)) {
+ return r;
+ }
+ r = target->getfilekeys(package->control, &filekeys);
+ if (!RET_IS_OK(r)) {
+ strlist_done(&binary);
+ return r;
+ }
+ for (i = 0 ; i < filekeys.count ; i++) {
+ if (endswith(filekeys.values[i], ".dsc")) {
+ dscfilename = filekeys.values[i];
+ break;
+ }
+ }
+ if (dscfilename == NULL) {
+ fprintf(stderr,
+"Warning: source package '%s' in '%s' without dsc file!\n",
+ package->name, target->identifier);
+ strlist_done(&binary);
+ strlist_done(&filekeys);
+ return RET_NOTHING;
+ }
+
+ if (d->tracks != NULL) {
+ struct trackedpackage *tp;
+
+ r = tracking_get(d->tracks, package->name, package->version, &tp);
+ if (RET_WAS_ERROR(r)) {
+ strlist_done(&binary);
+ strlist_done(&filekeys);
+ return r;
+ }
+ if (RET_IS_OK(r)) {
+ r = tracked_source_needs_build(
+ d->architecture, package->name,
+ package->version, dscfilename,
+ &binary, tp, d->printarch);
+ trackedpackage_free(tp);
+ strlist_done(&binary);
+ strlist_done(&filekeys);
+ return r;
+ }
+ fprintf(stderr,
+"Warning: %s's tracking data of %s (%s) is out of date. Run retrack to repair!\n",
+ target->distribution->codename,
+ package->name, package->version);
+ }
+ // TODO: implement without tracking
+ strlist_done(&binary);
+ strlist_done(&filekeys);
+ return RET_NOTHING;
+}
+
+
+retvalue find_needs_build(struct distribution *distribution, architecture_t architecture, const struct atomlist *onlycomponents, const char *glob, bool printarch) {
+ retvalue result, r;
+ struct needbuild_data d;
+
+ d.architecture = architecture;
+ d.glob = glob;
+ d.printarch = printarch;
+
+ if (distribution->tracking == dt_NONE) {
+ fprintf(stderr,
+"ERROR: '%s' has no source package Tracking enabled and\n"
+"build-needing is currently only implemented for distributions where\n"
+"this is enabled.\n"
+"(i.e. you need to add e.g. Tracking: minimal in conf/distribution\n"
+"and run retrack (and repeat running it after every update and pull.)\n",
+ distribution->codename);
+ return RET_ERROR;
+ }
+
+ if (distribution->tracking != dt_NONE) {
+ r = tracking_initialize(&d.tracks, distribution, true);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (r == RET_NOTHING)
+ d.tracks = NULL;
+ } else
+ d.tracks = NULL;
+
+ result = package_foreach_c(distribution,
+ onlycomponents, architecture_source, pt_dsc,
+ check_source_needs_build, &d);
+
+ r = tracking_done(d.tracks, distribution);
+ RET_ENDUPDATE(result, r);
+ return result;
+}