Source: gettext
Version: 0.19.7-2
Severity: wishlist
Tags: patch upstream
User: reproducible-bui...@lists.alioth.debian.org
Usertags: toolchain
X-Debbugs-Cc: reproducible-bui...@lists.alioth.debian.org

Dear Maintainer,

While working on the “reproducible builds” effort [1], we have noticed
that some packages (like gdm3, gnome-session) use xgettext in their
building process, resulting in timestamps in POT files that break
reproducibility.

To solve this kind of issues, it would be nice to have xgettext support
the SOURCE_DATE_EPOCH environment variable [2], so that the
POT-Creation-Date timestamp will be set from the last debian/changelog
entry instead of the (unreproducible) build date.

See the attached patch for a solution to this issue.

Regards,
Alexis Bienvenüe.

[1] https://wiki.debian.org/ReproducibleBuilds
[2] https://reproducible-builds.org/specs/source-date-epoch/


Description: xgettext honour SOURCE_DATE_EPOCH
 Make xgettext honour the SOURCE_DATE_EPOCH environment variable: is set,
 this variable is used to set POT-Creation-Date.
 See https://reproducible-builds.org/specs/source-date-epoch/
Author: Alexis Bienvenüe <p...@passoire.fr>

Index: gettext-0.19.7/gettext-tools/src/po-time.c
===================================================================
--- gettext-0.19.7.orig/gettext-tools/src/po-time.c
+++ gettext-0.19.7/gettext-tools/src/po-time.c
@@ -52,13 +52,17 @@ difftm (const struct tm *a, const struct
 
 
 char *
-po_strftime (const time_t *tp)
+po_strftime_tz (const time_t *tp, int gmt)
 {
   struct tm local_time;
   char tz_sign;
   long tz_min;
 
-  local_time = *localtime (tp);
+  if (gmt) {
+    local_time = *gmtime (tp);
+  } else {
+    local_time = *localtime (tp);
+  }
   tz_sign = '+';
   tz_min = difftm (&local_time, gmtime (tp)) / 60;
   if (tz_min < 0)
@@ -74,3 +78,9 @@ po_strftime (const time_t *tp)
                     local_time.tm_min,
                     tz_sign, tz_min / 60, tz_min % 60);
 }
+
+char *
+po_strftime (const time_t *tp)
+{
+  return (po_strftime_tz (tp,0));
+}
Index: gettext-0.19.7/gettext-tools/src/po-time.h
===================================================================
--- gettext-0.19.7.orig/gettext-tools/src/po-time.h
+++ gettext-0.19.7/gettext-tools/src/po-time.h
@@ -29,6 +29,7 @@ extern "C" {
 /* Return a freshly allocated string containing the given time in the
    format YYYY-MM-DD HH:MM+TZOFF.  */
 extern char *po_strftime (const time_t *tp);
+extern char *po_strftime_tz (const time_t *tp, int gmt);
 
 
 #ifdef __cplusplus
Index: gettext-0.19.7/gettext-tools/src/xgettext.c
===================================================================
--- gettext-0.19.7.orig/gettext-tools/src/xgettext.c
+++ gettext-0.19.7/gettext-tools/src/xgettext.c
@@ -3723,6 +3723,9 @@ construct_header ()
   message_ty *mp;
   char *msgstr;
   char *comment;
+  char *source_date_epoch;
+  unsigned long long epoch;
+  char *endptr;
   static lex_pos_ty pos = { __FILE__, __LINE__ };
 
   if (package_name != NULL)
@@ -3744,8 +3747,33 @@ the MSGID_BUGS_ADDRESS variable there; o
 specify an --msgid-bugs-address command line option.\n\
 ")));
 
-  time (&now);
-  timestring = po_strftime (&now);
+  source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+  if (source_date_epoch) {
+    errno = 0;
+    epoch = strtoull(source_date_epoch, &endptr, 10);
+    if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
+        || (errno != 0 && epoch == 0)) {
+      fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: strtoull: 
%s\n", strerror(errno));
+      exit(EXIT_FAILURE);
+    }
+    if (endptr == source_date_epoch) {
+      fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: No digits were 
found: %s\n", endptr);
+      exit(EXIT_FAILURE);
+    }
+    if (*endptr != '\0') {
+      fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: Trailing 
garbage: %s\n", endptr);
+      exit(EXIT_FAILURE);
+    }
+    if (epoch > ULONG_MAX) {
+      fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: value must be 
smaller than or equal to: %lu but was found to be: %llu \n", ULONG_MAX, epoch);
+      exit(EXIT_FAILURE);
+    }
+    now = epoch;
+    timestring = po_strftime_tz (&now,1);
+  } else {
+    time (&now);
+    timestring = po_strftime (&now);
+  }
 
   msgstr = xasprintf ("\
 Project-Id-Version: %s\n\

Reply via email to