Jérémy Bobbio:
> The first patch will modify `dpkg-deb` to use the same timestamp for
> every member of the ar archive.
> 
> The second patch will:
> 
>  1. Make `dpkg-deb` try to look for a timestamp to use in the
>     DEB_BUILD_TIMESTAMP environment variable in epoch format.
>     If not set or not parseable, it will default to use the current
>     time.
>  2. Change `dpkg-buildpackage` to parse `debian/changelog` and preset
>     DEB_BUILD_TIMESTAMP to the value of its latest entry. Unless
>     DEB_BUILD_TIMESTAMP was already set in order to allow arbitrary
>     dates to be reproduced.

The patches rebased on current master are attached (36eda4c1bc).

-- 
Lunar                                .''`. 
[email protected]                    : :Ⓐ  :  # apt-get install anarchism
                                    `. `'` 
                                      `-   
From 075bc4fd3d83604f0b38819179f559165bc75779 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <[email protected]>
Date: Tue, 27 Aug 2013 22:38:31 +0200
Subject: [PATCH 1/2] Use a single timestamp for ar headers when building a
 .deb

In order to make build reproducible in the future, we now use a single
timestamp in all ar headers when creating a .deb.

Previously, each ar header would have the current time of its creation.
This level of precision is not really needed and the time of the beginning of
the build is good enough.

Address: #759999
---
 dpkg-deb/build.c   |   10 +++++++---
 dpkg-split/split.c |    4 ++--
 lib/dpkg/ar.c      |   13 +++++++------
 lib/dpkg/ar.h      |    4 ++--
 4 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
index e48b4bf..6406493 100644
--- a/dpkg-deb/build.c
+++ b/dpkg-deb/build.c
@@ -38,6 +38,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <time.h>
 
 #include <dpkg/i18n.h>
 #include <dpkg/dpkg.h>
@@ -500,6 +501,7 @@ do_build(const char *const *argv)
   int arfd;
   int p1[2], p2[2], gzfd;
   pid_t c1, c2;
+  time_t build_timestamp;
 
   /* Decode our arguments. */
   dir = *argv++;
@@ -546,6 +548,8 @@ do_build(const char *const *argv)
   }
   m_output(stdout, _("<standard output>"));
 
+  build_timestamp = time(NULL);
+
   /* Now that we have verified everything its time to actually
    * build something. Let's start by making the ar-wrapper. */
   arfd = creat(debar, 0644);
@@ -600,8 +604,8 @@ do_build(const char *const *argv)
             compressor_get_extension(control_compress_params.type));
 
     dpkg_ar_put_magic(debar, arfd);
-    dpkg_ar_member_put_mem(debar, arfd, DEBMAGIC, deb_magic, strlen(deb_magic));
-    dpkg_ar_member_put_file(debar, arfd, adminmember, gzfd, -1);
+    dpkg_ar_member_put_mem(debar, arfd, DEBMAGIC, deb_magic, build_timestamp, strlen(deb_magic));
+    dpkg_ar_member_put_file(debar, arfd, adminmember, gzfd, build_timestamp, -1);
   } else {
     internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor);
   }
@@ -671,7 +675,7 @@ do_build(const char *const *argv)
     if (lseek(gzfd, 0, SEEK_SET))
       ohshite(_("failed to rewind temporary file (%s)"), _("data member"));
 
-    dpkg_ar_member_put_file(debar, arfd, datamember, gzfd, -1);
+    dpkg_ar_member_put_file(debar, arfd, datamember, gzfd, build_timestamp, -1);
 
     close(gzfd);
   }
diff --git a/dpkg-split/split.c b/dpkg-split/split.c
index fe4b60e..68109dc 100644
--- a/dpkg-split/split.c
+++ b/dpkg-split/split.c
@@ -216,13 +216,13 @@ mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
 		              (intmax_t)st.st_size, (intmax_t)partsize,
 		              curpart, nparts, arch);
 		dpkg_ar_member_put_mem(file_dst.buf, fd_dst, PARTMAGIC,
-		                       partmagic.buf, partmagic.used);
+		                       partmagic.buf, time(NULL), partmagic.used);
 		varbuf_reset(&partmagic);
 
 		/* Write the data part. */
 		varbuf_printf(&partname, "data.%d", curpart);
 		dpkg_ar_member_put_file(file_dst.buf, fd_dst, partname.buf,
-		                        fd_src, cur_partsize);
+		                        fd_src, time(NULL), cur_partsize);
 		varbuf_reset(&partname);
 
 		close(fd_dst);
diff --git a/lib/dpkg/ar.c b/lib/dpkg/ar.c
index cf540a0..8613310 100644
--- a/lib/dpkg/ar.c
+++ b/lib/dpkg/ar.c
@@ -36,11 +36,12 @@
 #include <dpkg/ar.h>
 
 static void
-dpkg_ar_member_init(struct dpkg_ar_member *member, const char *name, off_t size)
+dpkg_ar_member_init(struct dpkg_ar_member *member, const char *name,
+                    time_t timestamp, off_t size)
 {
 	member->name = name;
 	member->size = size;
-	member->time = time(NULL);
+	member->time = timestamp;
 	member->mode = 0100644;
 	member->uid = 0;
 	member->gid = 0;
@@ -124,11 +125,11 @@ dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
 
 void
 dpkg_ar_member_put_mem(const char *ar_name, int ar_fd,
-                       const char *name, const void *data, size_t size)
+                       const char *name, const void *data, time_t timestamp, size_t size)
 {
 	struct dpkg_ar_member member;
 
-	dpkg_ar_member_init(&member, name, size);
+	dpkg_ar_member_init(&member, name, timestamp, size);
 	dpkg_ar_member_put_header(ar_name, ar_fd, &member);
 
 	/* Copy data contents. */
@@ -142,7 +143,7 @@ dpkg_ar_member_put_mem(const char *ar_name, int ar_fd,
 
 void
 dpkg_ar_member_put_file(const char *ar_name, int ar_fd,
-                        const char *name, int fd, off_t size)
+                        const char *name, int fd, time_t timestamp, off_t size)
 {
 	struct dpkg_error err;
 	struct dpkg_ar_member member;
@@ -155,7 +156,7 @@ dpkg_ar_member_put_file(const char *ar_name, int ar_fd,
 		size = st.st_size;
 	}
 
-	dpkg_ar_member_init(&member, name, size);
+	dpkg_ar_member_init(&member, name, timestamp, size);
 	dpkg_ar_member_put_header(ar_name, ar_fd, &member);
 
 	/* Copy data contents. */
diff --git a/lib/dpkg/ar.h b/lib/dpkg/ar.h
index 81a061e..c1b8bed 100644
--- a/lib/dpkg/ar.h
+++ b/lib/dpkg/ar.h
@@ -59,9 +59,9 @@ void dpkg_ar_put_magic(const char *ar_name, int ar_fd);
 void dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
                                struct dpkg_ar_member *member);
 void dpkg_ar_member_put_file(const char *ar_name, int ar_fd, const char *name,
-                             int fd, off_t size);
+                             int fd, time_t timestamp, off_t size);
 void dpkg_ar_member_put_mem(const char *ar_name, int ar_fd, const char *name,
-                            const void *data, size_t size);
+                            const void *data, time_t timestamp, size_t size);
 off_t dpkg_ar_member_get_size(const char *ar_name, struct ar_hdr *arh);
 
 /** @} */
-- 
1.7.10.4

From c17c29561a3a4229cd94df73330f7f02771107fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <[email protected]>
Date: Tue, 27 Aug 2013 23:53:22 +0200
Subject: [PATCH 2/2] Preset build timestamp to latest changelog entry

dpkg-buildpackage will set the DEB_BUILD_TIMESTAMP environment variable to the
date of the latest entry in debian/changelog. This enables build to be easily
reproduced as the dates captured in the `.deb` archives will be deterministic.

DEB_BUILD_TIMESTAMP can also be externaly set before running dpkg-buildpackage.
to reproduce the build with an arbitrary date.

Closes: #759999
---
 dpkg-deb/build.c             |   20 +++++++++++++++++++-
 scripts/dpkg-buildpackage.pl |    6 ++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
index 6406493..a320b98 100644
--- a/dpkg-deb/build.c
+++ b/dpkg-deb/build.c
@@ -487,6 +487,24 @@ pkg_get_pathname(const char *dir, struct pkginfo *pkg)
   return path;
 }
 
+static time_t
+get_build_timestamp(void)
+{
+  time_t timestamp;
+  const char *value;
+  char *end;
+
+  errno = 0;
+  value = getenv("DEB_BUILD_TIMESTAMP");
+  if (!value)
+    return time(NULL);
+
+  timestamp = strtol(value, &end, 10);
+  if (value == end || *end || errno != 0)
+    ohshite(_("unable to parse timestamp `%.255s'"), value);
+  return timestamp;
+}
+
 /**
  * Overly complex function that builds a .deb file.
  */
@@ -548,7 +566,7 @@ do_build(const char *const *argv)
   }
   m_output(stdout, _("<standard output>"));
 
-  build_timestamp = time(NULL);
+  build_timestamp = get_build_timestamp();
 
   /* Now that we have verified everything its time to actually
    * build something. Let's start by making the ar-wrapper. */
diff --git a/scripts/dpkg-buildpackage.pl b/scripts/dpkg-buildpackage.pl
index f678659..95c2eb7 100755
--- a/scripts/dpkg-buildpackage.pl
+++ b/scripts/dpkg-buildpackage.pl
@@ -411,6 +411,12 @@ if ($changedby) {
     $maintainer = mustsetvar($changelog->{maintainer}, _g('source changed by'));
 }
 
+if (!$ENV{DEB_BUILD_TIMESTAMP}) {
+    my $timestamp = `date -d'$changelog->{date}' +%s`;
+    chomp $timestamp;
+    $ENV{DEB_BUILD_TIMESTAMP} = $timestamp;
+}
+
 open my $arch_env, '-|', 'dpkg-architecture', "-a$targetarch",
     "-t$targetgnusystem", '-f' or subprocerr('dpkg-architecture');
 while (<$arch_env>) {
-- 
1.7.10.4

Attachment: signature.asc
Description: Digital signature

Reply via email to