Package: reprepro
Version: 4.13.1-1+b1
Severity: wishlist

(Deliberately not tagging this +patch right now, since Debian doesn't
officially support ddebs yet, and the archive layout looks likely to change.)

Ubuntu has a semi-separate archive for separate debug symbols, and
<https://wiki.debian.org/AutomaticDebugPackages> is the proposal to
add the same thing to Debian. It would be great if reprepro could
support them, too.

The attached patch is a proof-of-concept implementation: it treats them
as a mixture of .deb and .ddeb. It seems to work OK in conjunction with
Ubuntu's pkg-create-dbgsym.

Known omissions:

* The wiki page says "ddeb will have no override entries, so no priority
  or section". In my implementation, they can have override entries
  (sharing an override file with normal debs), although those are not
  mandatory, and they have whatever package and section they are given
  by pkg-create-dbgsym, currently Priority: extra and whatever Section
  was used by the ordinary deb.

* The wiki page says "ddeb will go into the component "debug", so will
  show up in ./pool/debug/" but in my implementation they go in
  pool/{main,contrib,non-free}. The wiki page lists "Do we need to
  split ddeb per main/contrib/non-free?" as an open issue, which is partly
  why I chose to sidestep that question for now.

* The wiki page says "Standalone Release/Packages in ./debug/dists/"
  but in my implementation they behave more like udebs: they go somewhere
  like dists/main/debug/binary-i386/main and are covered by the main
  Release file.

* ddebs seem to end up with a long Description, despite the wiki
  page saying they shouldn't. I think tha might be a pkg-create-dbgsym
  bug, though?

I hope this is a useful starting point anyway.

Regards,
    S
>From b1d737032fb3949bb018a0799b2ce457499c4c65 Mon Sep 17 00:00:00 2001
From: Simon McVittie <simon.mcvit...@collabora.co.uk>
Date: Tue, 26 Nov 2013 16:12:22 +0000
Subject: [PATCH 2/2] Add basic support for ddebs (Ubuntu-style -dbgsym
 packages)

For the moment they're treated a lot like udebs: they're copied into
the same pool as normal debs and udebs, and their package lists
go into a subdirectory. The pull/updates logic doesn't support
downloading them, since we don't yet know how Debian mirrors that
carry ddebs will be laid out (and Ubuntu uses a separate public-facing
archive for them).
---
 atoms.c        | 12 +++++++++---
 atoms.h        |  1 +
 changes.c      |  6 ++++--
 changes.h      |  6 +++---
 checkin.c      | 31 ++++++++++++++++++++++++++-----
 checkindeb.c   | 28 +++++++++++++++++++++++++++-
 contents.c     | 48 +++++++++++++++++++++++++++++++++++++++++++-----
 contents.h     |  1 +
 copypackages.c |  9 ++++++++-
 distribution.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 distribution.h |  7 ++++++-
 incoming.c     | 15 +++++++++++++++
 main.c         | 40 ++++++++++++++++++++++++++++++----------
 pull.c         |  2 ++
 target.c       | 25 +++++++++++++++++++++++++
 target.h       |  1 +
 tool.c         | 26 +++++++++++++++++++-------
 updates.c      |  3 +++
 18 files changed, 268 insertions(+), 38 deletions(-)

diff --git a/atoms.c b/atoms.c
index 25214ee..7fa980d 100644
--- a/atoms.c
+++ b/atoms.c
@@ -26,7 +26,7 @@
 
 const char **atoms_architectures;
 const char **atoms_components;
-const char * const packagetypes[4] = { "!!NONE!!", "dsc", "deb", "udeb" };
+const char * const packagetypes[5] = { "!!NONE!!", "dsc", "deb", "udeb", "ddeb" };
 const char **atoms_packagetypes = (const char **)&packagetypes;
 const char **atoms_commands;
 static int command_count;
@@ -159,6 +159,8 @@ packagetype_t packagetype_find(const char *value) {
 		return pt_deb;
 	else if (strcmp(value, "udeb") == 0)
 		return pt_udeb;
+	else if (strcmp(value, "ddeb") == 0)
+		return pt_ddeb;
 	else
 		return atom_unknown;
 }
@@ -169,8 +171,12 @@ packagetype_t packagetype_find_l(const char *value, size_t len) {
 			return pt_dsc;
 		else if (strncmp(value, "deb", 3) == 0)
 			return pt_deb;
-	} else if (len == 4 && strncmp(value, "udeb", 4) == 0)
-		return pt_udeb;
+	} else if (len == 4) {
+		if (strncmp(value, "udeb", 4) == 0)
+			return pt_udeb;
+		else if (strncmp(value, "ddeb", 4) == 0)
+			return pt_ddeb;
+	}
 	return atom_unknown;
 }
 
diff --git a/atoms.h b/atoms.h
index be78713..660adb4 100644
--- a/atoms.h
+++ b/atoms.h
@@ -19,6 +19,7 @@ enum atom_type { at_architecture, at_component, at_packagetype, at_command };
 #define pt_dsc ((packagetype_t)1)
 #define pt_deb ((packagetype_t)2)
 #define pt_udeb ((packagetype_t)3)
+#define pt_ddeb ((packagetype_t)4)
 
 #define atom_defined(a) ((a) > (atom_t)0)
 
diff --git a/changes.c b/changes.c
index 5d01754..259162b 100644
--- a/changes.c
+++ b/changes.c
@@ -166,6 +166,8 @@ retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_t
 		type = fe_DEB;
 	else if (l >= 5 && memcmp(p-5, ".udeb", 5) == 0)
 		type = fe_UDEB;
+	else if (l >= 5 && memcmp(p-5, ".ddeb", 5) == 0)
+		type = fe_DDEB;
 	else
 		type = fe_UNKNOWN;
 
@@ -189,7 +191,7 @@ retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_t
 		if (type == fe_DEB)
 			archend = versionstart + l - 4;
 		else {
-			assert (type == fe_UDEB);
+			assert (type == fe_UDEB || type == fe_DDEB);
 			archend = versionstart + l - 5;
 		}
 		if (archend - archstart == 6 &&
@@ -203,7 +205,7 @@ retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_t
 		const char *eoi;
 
 		/* without those, it gets more complicated.
-		 * It's not .deb or .udeb, so most likely a
+		 * It's not .deb or .udeb or .ddeb, so most likely a
 		 * source file (or perhaps a log (reprepro extension)) */
 
 		/* if it uses a known compression, things are easy,
diff --git a/changes.h b/changes.h
index 30ad136..84a03d0 100644
--- a/changes.h
+++ b/changes.h
@@ -7,14 +7,14 @@
 
 typedef enum {
 	fe_UNKNOWN=0,
-	fe_DEB, fe_UDEB,
+	fe_DEB, fe_UDEB, fe_DDEB,
 	fe_DSC, fe_DIFF, fe_ORIG, fe_TAR,
 	fe_ALTSRC,
 	fe_BYHAND, fe_LOG, fe_CHANGES
 } filetype;
 
-#define FE_PACKAGE(ft) ((ft) == fe_DEB || (ft) == fe_UDEB || (ft) == fe_DSC)
-#define FE_BINARY(ft) ((ft) == fe_DEB || (ft) == fe_UDEB)
+#define FE_PACKAGE(ft) ((ft) == fe_DEB || (ft) == fe_UDEB || (ft) == fe_DSC || (ft) == fe_DDEB)
+#define FE_BINARY(ft) ((ft) == fe_DEB || (ft) == fe_UDEB || (ft) == fe_DDEB)
 #define FE_SOURCE(ft) ((ft) == fe_DIFF || (ft) == fe_ORIG || (ft) == fe_TAR || (ft) == fe_DSC || (ft) == fe_UNKNOWN || (ft) == fe_ALTSRC)
 
 struct hash_data;
diff --git a/checkin.c b/checkin.c
index 02ba279..ba5331f 100644
--- a/checkin.c
+++ b/checkin.c
@@ -130,7 +130,7 @@ static void freeentries(/*@only@*/struct fileentry *entry) {
 		free(entry->section);
 		free(entry->priority);
 		free(entry->name);
-		if (entry->type == fe_DEB || entry->type == fe_UDEB)
+		if (FE_BINARY(entry->type))
 			deb_free(entry->pkg.deb);
 		 else if (entry->type == fe_DSC) {
 			 strlist_done(&entry->needed_filekeys);
@@ -207,6 +207,11 @@ static retvalue newentry(struct fileentry **entry, const char *fileline, const s
 		*ignoredlines_p = true;
 		return RET_NOTHING;
 	}
+	if (e->type == fe_DDEB && limitations_missed(packagetypes, pt_ddeb)) {
+		freeentries(e);
+		*ignoredlines_p = true;
+		return RET_NOTHING;
+	}
 	if (e->type != fe_LOG &&
 			e->architecture_into == architecture_source &&
 			strcmp(e->name, sourcename) != 0) {
@@ -1164,8 +1169,7 @@ static retvalue changes_checkpkgs(struct distribution *distribution, struct chan
 	e = changes->files;
 	while (e != NULL) {
 		char *fullfilename;
-		if (e->type != fe_DEB && e->type != fe_DSC
-				&& e->type != fe_UDEB) {
+		if (!FE_PACKAGE (e->type)) {
 			e = e->next;
 			continue;
 		}
@@ -1190,6 +1194,15 @@ static retvalue changes_checkpkgs(struct distribution *distribution, struct chan
 				e->filekey, e->checksums,
 				&changes->binaries,
 				changes->source, changes->sourceversion);
+		} else if (e->type == fe_DDEB) {
+			r = deb_prepare(&e->pkg.deb,
+				e->component, e->architecture_into,
+				e->section, e->priority,
+				pt_ddeb,
+				distribution, fullfilename,
+				e->filekey, e->checksums,
+				&changes->binaries,
+				changes->source, changes->sourceversion);
 		} else if (e->type == fe_DSC) {
 			if (!changes->isbinnmu || IGNORING(dscinbinnmu,
 "File '%s' looks like a source package, but this .changes looks like a binNMU\n"
@@ -1227,8 +1240,7 @@ static retvalue changes_includepkgs(struct distribution *distribution, struct ch
 
 	e = changes->files;
 	while (e != NULL) {
-		if (e->type != fe_DEB && e->type != fe_DSC
-				&& e->type != fe_UDEB && e->type != fe_LOG
+		if (!FE_PACKAGE (e->type) && e->type != fe_LOG
 				&& e->type != fe_BYHAND) {
 			e = e->next;
 			continue;
@@ -1244,6 +1256,15 @@ static retvalue changes_includepkgs(struct distribution *distribution, struct ch
 				pt_deb, distribution, trackingdata);
 			if (r == RET_NOTHING)
 				*missed_p = true;
+		} else if (e->type == fe_DDEB) {
+			r = deb_addprepared(e->pkg.deb,
+				/* architecture all needs this, the rest is
+				 * already filtered out */
+				(e->architecture_into == architecture_all)?
+					forcearchitectures:NULL,
+				pt_ddeb, distribution, trackingdata);
+			if (r == RET_NOTHING)
+				*missed_p = true;
 		} else if (e->type == fe_UDEB) {
 			r = deb_addprepared(e->pkg.deb,
 				/* architecture all needs this, the rest is
diff --git a/checkindeb.c b/checkindeb.c
index 5ef318c..95b9968 100644
--- a/checkindeb.c
+++ b/checkindeb.c
@@ -109,6 +109,8 @@ static retvalue deb_preparelocation(struct debpackage *pkg, component_t forcecom
 		binoverride = distribution->overrides.udeb;
 		components = &distribution->udebcomponents;
 	} else {
+		/* we use the deb overrides for ddebs too - ddebs aren't
+		 * meant to have overrides so this is probably fine */
 		binoverride = distribution->overrides.deb;
 		components = &distribution->components;
 	}
@@ -241,13 +243,37 @@ retvalue deb_prepare(/*@out@*/struct debpackage **deb, component_t forcecomponen
 	if (RET_WAS_ERROR(r)) {
 		return r;
 	}
-	if (!strlist_in(allowed_binaries, pkg->deb.name) &&
+
+	if (packagetype == pt_ddeb) {
+		/* ddebs are allowed if they are an allowed
+		 * binary + "-dbgsym" */
+		int i;
+		bool found = false;
+
+		for (i = 0; i < allowed_binaries->count; i++) {
+			const char *s = allowed_binaries->values[i];
+			size_t len = strlen(s);
+
+			if (strncmp(s, pkg->deb.name, len) == 0 &&
+					strcmp(pkg->deb.name + len, "-dbgsym") == 0) {
+				found = true;
+			}
+		}
+
+		if (!found && !IGNORING(surprisingbinary,
+					"'%s' has packagename '%s' not corresponding to a .deb listed in the .changes file!\n",
+					debfilename, pkg->deb.name)) {
+			deb_free(pkg);
+			return RET_ERROR;
+		}
+	} else if (!strlist_in(allowed_binaries, pkg->deb.name) &&
 	    !IGNORING(surprisingbinary,
 "'%s' has packagename '%s' not listed in the .changes file!\n",
 					debfilename, pkg->deb.name)) {
 		deb_free(pkg);
 		return RET_ERROR;
 	}
+
 	if (strcmp(pkg->deb.source, expectedsourcepackage) != 0) {
 		/* this cannot be ignored easily, as it determines
 		 * the directory this file is stored into */
diff --git a/contents.c b/contents.c
index 877e467..d38dd02 100644
--- a/contents.c
+++ b/contents.c
@@ -42,6 +42,7 @@ retvalue contentsoptions_parse(struct distribution *distribution, struct configi
 		cf_uncompressed, cf_gz, cf_bz2,
 		cf_percomponent, cf_allcomponents,
 		cf_compatsymlink, cf_nocompatsymlink,
+		cf_ddebs,
 		cf_COUNT
 	};
 	bool flags[cf_COUNT];
@@ -58,6 +59,7 @@ retvalue contentsoptions_parse(struct distribution *distribution, struct configi
 		{".bz2", cf_bz2},
 		{".gz", cf_gz},
 		{".", cf_uncompressed},
+		{"ddebs", cf_ddebs},
 		{NULL, -1}
 	};
 	retvalue r;
@@ -114,6 +116,7 @@ retvalue contentsoptions_parse(struct distribution *distribution, struct configi
 		distribution->contents.compressions |= IC_FLAG(ic_bzip2);
 #endif
 	distribution->contents.flags.udebs = flags[cf_udebs];
+	distribution->contents.flags.ddebs = flags[cf_ddebs];
 	distribution->contents.flags.nodebs = flags[cf_nodebs];
 	if (flags[cf_allcomponents])
 		distribution->contents.flags.allcomponents = true;
@@ -173,20 +176,36 @@ static retvalue gentargetcontents(struct target *target, struct release *release
 	struct filetorelease *file;
 	struct filelist_list *contents;
 	struct target_cursor iterator;
+	const char *suffix;
+	const char *symlink_prefix;
 
 	if (onlyneeded && target->saved_wasmodified)
 		onlyneeded = false;
 
+	switch (target->packagetype) {
+		case pt_ddeb:
+			symlink_prefix = "d";
+			suffix = "-ddeb";
+			break;
+		case pt_udeb:
+			symlink_prefix = "s";
+			suffix = "-udeb";
+			break;
+		default:
+			symlink_prefix = "";
+			suffix = "";
+	}
+
 	contentsfilename = mprintf("%s/Contents%s-%s",
 			atoms_components[target->component],
-			(target->packagetype == pt_udeb)?"-udeb":"",
+			suffix,
 			atoms_architectures[target->architecture]);
 	if (FAILEDTOALLOC(contentsfilename))
 		return RET_ERROR_OOM;
 
 	if (symlink) {
 		char *symlinkas = mprintf("%sContents-%s",
-				(target->packagetype == pt_udeb)?"s":"",
+				symlink_prefix,
 				atoms_architectures[target->architecture]);
 		if (FAILEDTOALLOC(symlinkas)) {
 			free(contentsfilename);
@@ -247,17 +266,30 @@ static retvalue genarchcontents(struct distribution *distribution, architecture_
 	const struct atomlist *components;
 	struct target *target;
 	bool combinedonlyifneeded;
+	const char *prefix;
+	const char *symlink_prefix;
 
-	if (type == pt_udeb) {
+	if (type == pt_ddeb) {
+		if (distribution->contents_components_set)
+			components = &distribution->contents_dcomponents;
+		else
+			components = &distribution->ddebcomponents;
+		prefix = "d";
+		symlink_prefix = "d";
+	} else if (type == pt_udeb) {
 		if (distribution->contents_components_set)
 			components = &distribution->contents_ucomponents;
 		else
 			components = &distribution->udebcomponents;
+		prefix = "u";
+		symlink_prefix = "s";
 	} else {
 		if (distribution->contents_components_set)
 			components = &distribution->contents_components;
 		else
 			components = &distribution->components;
+		prefix = "";
+		symlink_prefix = "";
 	}
 
 	if (components->count == 0)
@@ -289,7 +321,7 @@ static retvalue genarchcontents(struct distribution *distribution, architecture_
 	if (!distribution->contents.flags.allcomponents) {
 		if (!distribution->contents.flags.compatsymlink) {
 			char *symlinkas = mprintf("%sContents-%s",
-					(type == pt_udeb)?"s":"",
+					symlink_prefix,
 					atoms_architectures[architecture]);
 			if (FAILEDTOALLOC(symlinkas))
 				return RET_ERROR_OOM;
@@ -301,7 +333,7 @@ static retvalue genarchcontents(struct distribution *distribution, architecture_
 	}
 
 	contentsfilename = mprintf("%sContents-%s",
-			(type == pt_udeb)?"u":"",
+			prefix,
 			atoms_architectures[architecture]);
 	if (FAILEDTOALLOC(contentsfilename))
 		return RET_ERROR_OOM;
@@ -368,6 +400,12 @@ retvalue contents_generate(struct distribution *distribution, struct release *re
 					release, onlyneeded);
 			RET_UPDATE(result, r);
 		}
+		if (distribution->contents.flags.ddebs) {
+			r = genarchcontents(distribution,
+					architecture, pt_ddeb,
+					release, onlyneeded);
+			RET_UPDATE(result, r);
+		}
 	}
 	return result;
 }
diff --git a/contents.h b/contents.h
index 921f6a0..b8a214d 100644
--- a/contents.h
+++ b/contents.h
@@ -19,6 +19,7 @@ struct contentsoptions {
 		bool percomponent;
 		bool allcomponents;
 		bool compatsymlink;
+		bool ddebs;
 	} flags;
 	compressionset compressions;
 };
diff --git a/copypackages.c b/copypackages.c
index 1b37977..57a9745 100644
--- a/copypackages.c
+++ b/copypackages.c
@@ -830,7 +830,14 @@ retvalue copy_from_file(struct distribution *into, component_t component, archit
 					into->codename,
 					atoms_architectures[architecture]);
 		}
-		if (packagetype != pt_udeb) {
+		if (packagetype == pt_ddeb) {
+			if (!atomlist_in(&into->ddebcomponents, component)) {
+				fprintf(stderr,
+"Distribution '%s' does not contain ddeb component '%s!'\n",
+					into->codename,
+					atoms_components[component]);
+			}
+		} else if (packagetype != pt_udeb) {
 			if (!atomlist_in(&into->components, component)) {
 				fprintf(stderr,
 "Distribution '%s' does not contain component '%s!'\n",
diff --git a/distribution.c b/distribution.c
index 6db17da..f487e50 100644
--- a/distribution.c
+++ b/distribution.c
@@ -68,8 +68,10 @@ static retvalue distribution_free(struct distribution *distribution) {
 		exportmode_done(&distribution->dsc);
 		exportmode_done(&distribution->deb);
 		exportmode_done(&distribution->udeb);
+		exportmode_done(&distribution->ddeb);
 		atomlist_done(&distribution->contents_architectures);
 		atomlist_done(&distribution->contents_components);
+		atomlist_done(&distribution->contents_dcomponents);
 		atomlist_done(&distribution->contents_ucomponents);
 		override_free(distribution->overrides.deb);
 		override_free(distribution->overrides.udeb);
@@ -181,6 +183,25 @@ static retvalue createtargets(struct distribution *distribution) {
 					return r;
 
 			}
+			if (atomlist_in(&distribution->ddebcomponents, c)) {
+				r = target_initialize_dbinary(
+						distribution,
+						c, a,
+						&distribution->ddeb,
+						distribution->readonly,
+						distribution->fakecomponentprefix,
+						&t);
+				if (RET_IS_OK(r)) {
+					if (last != NULL) {
+						last->next = t;
+					} else {
+						distribution->targets = t;
+					}
+					last = t;
+				}
+				if (RET_WAS_ERROR(r))
+					return r;
+			}
 		}
 		/* check if this distribution contains source
 		 * (yes, yes, source is not really an architecture, but
@@ -221,6 +242,11 @@ CFstartparse(distribution) {
 		(void)distribution_free(n);
 		return r;
 	}
+	r = exportmode_init(&n->ddeb, true, "Release", "Packages");
+	if (RET_WAS_ERROR(r)) {
+		(void)distribution_free(n);
+		return r;
+	}
 	r = exportmode_init(&n->deb, true, "Release", "Packages");
 	if (RET_WAS_ERROR(r)) {
 		(void)distribution_free(n);
@@ -323,6 +349,9 @@ CFfinishparse(distribution) {
 	    notpropersuperset(&n->components, "Components",
 			    &n->contents_components, "ContentsComponents",
 			    atoms_components, n) ||
+	    notpropersuperset(&n->ddebcomponents, "DDebComponents",
+			    &n->contents_dcomponents, "ContentsDComponents",
+			    atoms_components, n) ||
 	    notpropersuperset(&n->udebcomponents, "UDebComponents",
 			    &n->contents_ucomponents, "ContentsUComponents",
 			    atoms_components, n) ||
@@ -330,6 +359,9 @@ CFfinishparse(distribution) {
 	    // in the rest of the code...:
 	    notpropersuperset(&n->components, "Components",
 			    &n->udebcomponents, "UDebComponents",
+			    atoms_components, n) ||
+	    notpropersuperset(&n->components, "Components",
+			    &n->ddebcomponents, "DDebComponents",
 			    atoms_components, n)) {
 		(void)distribution_free(n);
 		return RET_ERROR;
@@ -351,6 +383,14 @@ CFfinishparse(distribution) {
 			n->contents.flags.udebs = false;
 		}
 	}
+	if (n->contents_dcomponents_set) {
+		if (n->contents_dcomponents.count > 0) {
+			n->contents.flags.enabled = true;
+			n->contents.flags.ddebs = true;
+		} else {
+			n->contents.flags.ddebs = false;
+		}
+	}
 	if (n->contents_architectures_set) {
 		if (n->contents_architectures.count > 0)
 			n->contents.flags.enabled = true;
@@ -404,8 +444,11 @@ CFinternatomsSETPROC(distribution, components, checkforcomponent, at_component)
 CFinternatomsSETPROC(distribution, architectures, checkforarchitecture, at_architecture)
 CFatomsublistSETPROC(distribution, contents_architectures, at_architecture, architectures, "Architectures")
 CFatomsublistSETPROC(distribution, contents_components, at_component, components, "Components")
+CFatomsublistSETPROC(distribution, ddebcomponents, at_component, components, "Components")
 CFatomsublistSETPROC(distribution, udebcomponents, at_component, components, "Components")
+CFatomsublistSETPROC(distribution, contents_dcomponents, at_component, ddebcomponents, "DDebComponents")
 CFatomsublistSETPROC(distribution, contents_ucomponents, at_component, udebcomponents, "UDebComponents")
+CFexportmodeSETPROC(distribution, ddeb)
 CFexportmodeSETPROC(distribution, udeb)
 CFexportmodeSETPROC(distribution, deb)
 CFexportmodeSETPROC(distribution, dsc)
@@ -443,6 +486,8 @@ static const struct configfield distributionconfigfields[] = {
 	CF("ContentsComponents", distribution,	contents_components),
 	CF("Contents",		distribution,	Contents),
 	CF("ContentsUComponents", distribution,	contents_ucomponents),
+	CF("DDebComponents",	distribution,	ddebcomponents),
+	CF("DDebIndices",	distribution,	ddeb),
 	CF("DebIndices",	distribution,	deb),
 	CF("DebOverride",	distribution,	deb_override),
 	CF("Description",	distribution,	description),
diff --git a/distribution.h b/distribution.h
index 80c7bb8..1fb2cec 100644
--- a/distribution.h
+++ b/distribution.h
@@ -57,8 +57,10 @@ struct distribution {
 	/* the list of components containing a debian-installer dir,
 	 * normally only "main" */
 	struct atomlist udebcomponents;
+	/* the list of components containing a debug directory */
+	struct atomlist ddebcomponents;
 	/* what kind of index files to generate */
-	struct exportmode dsc, deb, udeb;
+	struct exportmode dsc, deb, udeb, ddeb;
 	/* is tracking enabled for this distribution?
 	 * (NONE must be 0 so it is the default) */
 	enum trackingtype { dt_NONE=0, dt_KEEP, dt_ALL, dt_MINIMAL } tracking;
@@ -73,11 +75,14 @@ struct distribution {
 	struct contentsoptions contents;
 	struct atomlist contents_architectures,
 		       contents_components,
+		       contents_dcomponents,
 		       contents_ucomponents;
 	bool contents_architectures_set,
 		       contents_components_set,
+		       contents_dcomponents_set,
 		       contents_ucomponents_set,
 		       /* not used, just here to keep things simpler: */
+		       ddebcomponents_set,
 		       udebcomponents_set;
 	/* A list of all targets contained in the distribution*/
 	struct target *targets;
diff --git a/incoming.c b/incoming.c
index e53b046..53df5f2 100644
--- a/incoming.c
+++ b/incoming.c
@@ -1164,9 +1164,13 @@ static retvalue prepare_deb(const struct incoming *i, const struct candidate *c,
 	assert (file == package->master);
 	if (file->type == fe_DEB)
 		package->packagetype = pt_deb;
+	else if (file->type == fe_DDEB)
+		package->packagetype = pt_ddeb;
 	else
 		package->packagetype = pt_udeb;
 
+	/* we use the deb overrides for ddebs too - ddebs aren't
+	 * meant to have overrides so this is probably fine */
 	oinfo = override_search(file->type==fe_UDEB?into->overrides.udeb:
 			                    into->overrides.deb,
 	                        file->name);
@@ -1177,6 +1181,16 @@ static retvalue prepare_deb(const struct incoming *i, const struct candidate *c,
 	if (RET_WAS_ERROR(r))
 		return r;
 
+	if (file->type == fe_DDEB &&
+	    !atomlist_in(&into->ddebcomponents, package->component)) {
+		fprintf(stderr,
+"Cannot put file '%s' of '%s' into component '%s',\n"
+"as it is not listed in DDebComponents of '%s'!\n",
+			BASENAME(i, file->ofs), BASENAME(i, c->ofs),
+			atoms_components[package->component],
+			into->codename);
+		return RET_ERROR;
+	}
 	if (file->type == fe_UDEB &&
 	    !atomlist_in(&into->udebcomponents, package->component)) {
 		fprintf(stderr,
@@ -1564,6 +1578,7 @@ static retvalue prepare_for_distribution(const struct incoming *i, const struct
 		switch (file->type) {
 			case fe_UDEB:
 			case fe_DEB:
+			case fe_DDEB:
 				r = prepare_deb(i, c, d, file);
 				break;
 			case fe_DSC:
diff --git a/main.c b/main.c
index 3cc11db..932e4af 100644
--- a/main.c
+++ b/main.c
@@ -2490,7 +2490,9 @@ static retvalue repair_descriptions(struct target *target, bool force) {
         const char *package, *controlchunk;
 
         assert(target->packages == NULL);
-	assert(target->packagetype == pt_deb || target->packagetype == pt_udeb);
+	assert(target->packagetype == pt_deb ||
+			target->packagetype == pt_udeb ||
+			target->packagetype == pt_ddeb);
 
         if (verbose > 2) {
                 printf(
@@ -2510,7 +2512,8 @@ static retvalue repair_descriptions(struct target *target, bool force) {
 			break;
 		}
                 r = description_complete(package, controlchunk,
-				target->packagetype == pt_udeb,
+				(target->packagetype == pt_udeb ||
+					target->packagetype == pt_ddeb),
 				force, &newcontrolchunk);
                 RET_UPDATE(result, r);
                 if (RET_WAS_ERROR(r))
@@ -2636,7 +2639,7 @@ ACTION_RF(n, n, y, y, sizes) {
 ACTION_D(y, y, y, includedeb) {
 	retvalue result, r;
 	struct distribution *distribution;
-	bool isudeb;
+	packagetype_t packagetype;
 	trackingdb tracks;
 	int i = 0;
 	component_t component = atom_unknown;
@@ -2659,14 +2662,21 @@ ACTION_D(y, y, y, includedeb) {
 			return RET_ERROR;
 		}
 	if (strcmp(argv[0], "includeudeb") == 0) {
-		isudeb = true;
+		packagetype = pt_udeb;
 		if (limitations_missed(packagetypes, pt_udeb)) {
 			fprintf(stderr,
 "Calling includeudeb with a -T not containing udeb makes no sense!\n");
 			return RET_ERROR;
 		}
+	} else if (strcmp(argv[0], "includeddeb") == 0) {
+		packagetype = pt_ddeb;
+		if (limitations_missed(packagetypes, pt_ddeb)) {
+			fprintf(stderr,
+"Calling includeddeb with a -T not containing ddeb makes no sense!\n");
+			return RET_ERROR;
+		}
 	} else if (strcmp(argv[0], "includedeb") == 0) {
-		isudeb = false;
+		packagetype = pt_deb;
 		if (limitations_missed(packagetypes, pt_deb)) {
 			fprintf(stderr,
 "Calling includedeb with a -T not containing deb makes no sense!\n");
@@ -2681,10 +2691,14 @@ ACTION_D(y, y, y, includedeb) {
 	for (i = 2 ; i < argc ; i++) {
 		const char *filename = argv[i];
 
-		if (isudeb) {
+		if (packagetype == pt_udeb) {
 			if (!endswith(filename, ".udeb") && !IGNORING(extension,
 "includeudeb called with file '%s' not ending with '.udeb'\n", filename))
 				return RET_ERROR;
+		} else if (packagetype == pt_ddeb) {
+			if (!endswith(filename, ".ddeb") && !IGNORING(extension,
+"includeddeb called with file '%s' not ending with '.ddeb'\n", filename))
+				return RET_ERROR;
 		} else {
 			if (!endswith(filename, ".deb") && !IGNORING(extension,
 "includedeb called with file '%s' not ending with '.deb'\n", filename))
@@ -2703,10 +2717,12 @@ ACTION_D(y, y, y, includedeb) {
 		return RET_ERROR;
 	}
 
-	if (isudeb)
+	if (packagetype == pt_udeb)
 		result = override_read(distribution->udeb_override,
 				&distribution->overrides.udeb, false);
 	else
+		/* we use the normal deb overrides for ddebs too -
+		 * they're not meant to have overrides anyway */
 		result = override_read(distribution->deb_override,
 				&distribution->overrides.deb, false);
 	if (RET_WAS_ERROR(result)) {
@@ -2745,7 +2761,7 @@ ACTION_D(y, y, y, includedeb) {
 		const char *filename = argv[i];
 
 		r = deb_add(component, architectures,
-				section, priority, isudeb?pt_udeb:pt_deb,
+				section, priority, packagetype,
 				distribution, filename,
 				delete, tracks);
 		RET_UPDATE(result, r);
@@ -3955,6 +3971,8 @@ static const struct action {
 		2, -1, "[--delete] includedeb <distribution> <.deb-file>"},
 	{"includeudeb",		A_Dactsp(includedeb)|NEED_DELNEW,
 		2, -1, "[--delete] includeudeb <distribution> <.udeb-file>"},
+	{"includeddeb",		A_Dactsp(includedeb)|NEED_DELNEW,
+		2, -1, "[--delete] includeddeb <distribution> <.ddeb-file>"},
 	{"includedsc",		A_Dactsp(includedsc)|NEED_DELNEW,
 		2, 2, "[--delete] includedsc <distribution> <package>"},
 	{"include",		A_Dactsp(include)|NEED_DELNEW,
@@ -4143,7 +4161,7 @@ static retvalue callaction(command_t command, const struct action *action, int a
 			if (r == RET_NOTHING) {
 				fprintf(stderr,
 "Error: Packagetype '%s' as given to --packagetype is not know.\n"
-"(only dsc, deb, udeb and combinations of those are allowed)\n",
+"(only dsc, deb, udeb, ddeb and combinations of those are allowed)\n",
 					unknownitem);
 				r = RET_ERROR;
 			}
@@ -4410,7 +4428,7 @@ static void handle_option(int c, const char *argument) {
 " -P, --priority <priority>:         Force include* to set priority.\n"
 " -C, --component <component>: 	     Add,list or delete only in component.\n"
 " -A, --architecture <architecture>: Add,list or delete only to architecture.\n"
-" -T, --type <type>:                 Add,list or delete only type (dsc,deb,udeb).\n"
+" -T, --type <type>:                 Add,list or delete only type (dsc,deb,udeb,ddeb).\n"
 "\n"
 "actions (selection, for more see manpage):\n"
 " dumpreferences:    Print all saved references\n"
@@ -4429,6 +4447,8 @@ static void handle_option(int c, const char *argument) {
 "       Include the given upload.\n"
 " includedeb <distribution> <.deb-file>\n"
 "       Include the given binary package.\n"
+" includeddeb <distribution> <.ddeb-file>\n"
+"       Include the given debug binary package.\n"
 " includeudeb <distribution> <.udeb-file>\n"
 "       Include the given installer binary package.\n"
 " includedsc <distribution> <.dsc-file>\n"
diff --git a/pull.c b/pull.c
index 99922b4..1a64b81 100644
--- a/pull.c
+++ b/pull.c
@@ -59,6 +59,8 @@ struct pull_rule {
 	//e.g. "UDebComponents: main" // (not set means all)
 	struct atomlist udebcomponents;
 	bool udebcomponents_set;
+	// We don't have equivalents for ddebs yet since we don't know
+	// what the Debian archive layout is going to look like
 	// NULL means no condition
 	/*@null@*/term *includecondition;
 	struct filterlist filterlist;
diff --git a/target.c b/target.c
index 2a6ca52..f0daa02 100644
--- a/target.c
+++ b/target.c
@@ -51,6 +51,10 @@ static char *calc_identifier(const char *codename, component_t component, archit
 		return mprintf("u|%s|%s|%s", codename,
 				atoms_components[component],
 				atoms_architectures[architecture]);
+	else if (packagetype == pt_ddeb)
+		return mprintf("d|%s|%s|%s", codename,
+				atoms_components[component],
+				atoms_architectures[architecture]);
 	else
 		return mprintf("%s|%s|%s", codename,
 				atoms_components[component],
@@ -128,6 +132,27 @@ retvalue target_initialize_ubinary(struct distribution *d, component_t component
 				atoms_architectures[architecture]),
 			exportmode, readonly, target);
 }
+
+retvalue target_initialize_dbinary(struct distribution *d, component_t component, architecture_t architecture, const struct exportmode *exportmode, bool readonly, const char *fakecomponentprefix, struct target **target) {
+	return target_initialize(d, component, architecture, pt_ddeb,
+			binaries_getversion,
+			binaries_getinstalldata,
+			binaries_getarchitecture,
+			binaries_getfilekeys, binaries_getchecksums,
+			binaries_getsourceandversion,
+			/* we use the main overrides */
+			binaries_doreoverride, binaries_retrack,
+			binaries_complete_checksums,
+			/* FIXME: we don't know what the Debian archive layout
+			 * is going to look like yet, so take a guess based
+			 * on udebs */
+			mprintf("%s/debug/binary-%s",
+				dist_component_name(component,
+					fakecomponentprefix),
+				atoms_architectures[architecture]),
+			exportmode, readonly, target);
+}
+
 retvalue target_initialize_binary(struct distribution *d, component_t component, architecture_t architecture, const struct exportmode *exportmode, bool readonly, const char *fakecomponentprefix, struct target **target) {
 	return target_initialize(d, component, architecture, pt_deb,
 			binaries_getversion,
diff --git a/target.h b/target.h
index baddd82..d55c947 100644
--- a/target.h
+++ b/target.h
@@ -74,6 +74,7 @@ struct target {
 };
 
 retvalue target_initialize_ubinary(/*@dependant@*/struct distribution *, component_t, architecture_t, /*@dependent@*/const struct exportmode *, bool /*readonly*/, /*@NULL@*/const char *fakecomponentprefix, /*@out@*/struct target **);
+retvalue target_initialize_dbinary(/*@dependant@*/struct distribution *, component_t, architecture_t, /*@dependent@*/const struct exportmode *, bool /*readonly*/, /*@NULL@*/const char *fakecomponentprefix, /*@out@*/struct target **);
 retvalue target_initialize_binary(/*@dependant@*/struct distribution *, component_t, architecture_t, /*@dependent@*/const struct exportmode *, bool /*readonly*/, /*@NULL@*/const char *fakecomponentprefix, /*@out@*/struct target **);
 retvalue target_initialize_source(/*@dependant@*/struct distribution *, component_t, /*@dependent@*/const struct exportmode *, bool /*readonly*/, /*@NULL@*/const char *fakecomponentprefix, /*@out@*/struct target **);
 retvalue target_free(struct target *);
diff --git a/tool.c b/tool.c
index e2479ba..25f8a5a 100644
--- a/tool.c
+++ b/tool.c
@@ -98,12 +98,18 @@ static void binaryfile_free(struct binaryfile *p) {
 	free(p);
 }
 
+/* This is pretty close to duplicating the enum typedef'd to filetype
+ * in changes.h, but its order corresponds to typesuffix[]. Do not
+ * confuse them. */
 enum filetype { ft_UNKNOWN,
 			ft_TAR, ft_ORIG_TAR, ft_DIFF,
 #define ft_MaxInSource ft_DSC-1
-			ft_DSC, ft_DEB, ft_UDEB , ft_Count};
+			ft_DSC, ft_DEB, ft_UDEB , ft_DDEB, ft_Count};
 #define ft_Max ft_Count-1
 
+/* Analogous to FE_BINARY, but for enum filetype. */
+#define FT_BINARY(ft) ((ft) == ft_DEB || (ft) == ft_UDEB || (ft) == ft_DDEB)
+
 static const struct {
 	const char *suffix;
 	size_t len;
@@ -115,7 +121,8 @@ static const struct {
 	{ ".diff", 5, true},
 	{ ".dsc", 4, false},
 	{ ".deb", 4, false},
-	{ ".udeb", 5, false}
+	{ ".udeb", 5, false},
+	{ ".ddeb", 5, false}
 };
 
 struct dscfile {
@@ -158,7 +165,7 @@ struct fileentry {
 	char *section, *priority;
 	enum filetype type;
 	enum compression compression;
-	/* only if type deb or udeb */
+	/* only if type deb or udeb or ddeb */
 	struct binaryfile *deb;
 	/* only if type dsc */
 	struct dscfile *dsc;
@@ -199,7 +206,7 @@ static void fileentry_free(/*@only@*/struct fileentry *f) {
 	checksums_free(f->realchecksums);
 	free(f->section);
 	free(f->priority);
-	if (f->type == ft_DEB || f->type == ft_UDEB) {
+	if (FT_BINARY(f->type)) {
 		binaryfile_free(f->deb);
 	} else if (f->type == ft_DSC) {
 		dscfile_free(f->dsc);
@@ -947,7 +954,7 @@ static retvalue processfiles(const char *changesfilename, struct changes *change
 		if (RET_IS_OK(r)) {
 			if (file->type == ft_DSC)
 				r = parse_dsc(file, changes);
-			else if (file->type == ft_DEB || file->type == ft_UDEB)
+			else if (FT_BINARY(file->type))
 				r = parse_deb(file, changes);
 			if (RET_WAS_ERROR(r)) {
 				free(dir);
@@ -958,7 +965,7 @@ static retvalue processfiles(const char *changesfilename, struct changes *change
 		if (r == RET_NOTHING) {
 			/* apply heuristics when not readable */
 			if (file->type == ft_DSC) {
-			} else if (file->type == ft_DEB || file->type == ft_UDEB) {
+			} else if (FT_BINARY(file->type)) {
 				struct binary *b; size_t len;
 
 				len = 0;
@@ -1819,7 +1826,7 @@ static retvalue verify(const char *changesfilename, struct changes *changes) {
 		const struct binary *b;
 		const struct binaryfile *deb;
 
-		if (file->type != ft_DEB && file->type != ft_UDEB)
+		if (!FT_BINARY(file->type))
 			continue;
 		if (file->fullfilename == NULL) {
 			fprintf(stderr,
@@ -2504,6 +2511,10 @@ static retvalue adddeb(struct changes *c, const char *debfilename, const struct
 			strcmp(fullfilename+strlen(fullfilename)-5, ".udeb") == 0) {
 		packagetype = "udeb";
 		type = ft_UDEB;
+	} else if (strlen(fullfilename) > 5 &&
+			strcmp(fullfilename+strlen(fullfilename)-5, ".ddeb") == 0) {
+		packagetype = "ddeb";
+		type = ft_DDEB;
 	} else {
 		packagetype = "deb";
 		type = ft_DEB;
@@ -2767,6 +2778,7 @@ static retvalue addfiles(const char *changesfilename, struct changes *c, int arg
 		size_t l = strlen(filename);
 
 		if ((l > 4 && strcmp(filename+l-4, ".deb") == 0) ||
+		    (l > 5 && strcmp(filename+l-5, ".ddeb") == 0) ||
 		    (l > 5 && strcmp(filename+l-5, ".udeb") == 0))
 			r = adddeb(c, filename, searchpath);
 		else if ((l > 4 && strcmp(filename+l-4, ".dsc") == 0))
diff --git a/updates.c b/updates.c
index ab4de35..0772203 100644
--- a/updates.c
+++ b/updates.c
@@ -153,6 +153,9 @@ struct update_pattern {
 	// (empty means all)
 	struct strlist udebcomponents_from;
 	struct strlist udebcomponents_into;
+	// There's no ddeb support here yet, since we don't know what the
+	// Debian archive layout is going to look like.
+
 	// NULL means no condition
 	/*@null@*/term *includecondition;
 	struct filterlist filterlist;
-- 
1.8.4.4

Reply via email to