Source: sphinx Version: 1.3.6-2 Severity: wishlist Tags: patch upstream User: reproducible-builds@lists.alioth.debian.org Usertags: toolchain X-Debbugs-Cc: reproducible-builds@lists.alioth.debian.org
Dear Maintainer, While working on the “reproducible builds” effort [1], we have noticed that, even though sphinx honours the SOURCE_DATE_EPOCH environment variable [2], this support is still incomplete: default copyright year and gettext don't use it. Various packages (eg. fabric, guidata) that build-depend on sphinx use a conf.py that sets the copyright year from current time, like copyright = u'2006-%s, Author' % time.strftime('%Y') This also breaks reproducibility of the building process. The attached patch extends the SOURCE_DATE_EPOCH support in copyright year and gettext, and corrects copyright strings that does not corresponds to SOURCE_DATE_EPOCH, so that affected packages can be built reproducibly without any change. Regards, Alexis Bienvenüe. [1] https://wiki.debian.org/ReproducibleBuilds [2] https://reproducible-builds.org/specs/source-date-epoch/
diff -Nru sphinx-1.3.6/debian/changelog sphinx-1.3.6/debian/changelog --- sphinx-1.3.6/debian/changelog 2016-03-03 18:22:21.000000000 +0100 +++ sphinx-1.3.6/debian/changelog 2016-04-13 14:05:28.000000000 +0200 @@ -1,3 +1,9 @@ +sphinx (1.3.6-2.0~reproducible1) unstable; urgency=medium + + * Extends SOURCE_DATE_EPOCH support to copyright year. + + -- Alexis Bienvenüe <p...@passoire.fr> Wed, 13 Apr 2016 09:45:47 +0200 + sphinx (1.3.6-2) unstable; urgency=medium * Use implementation of jstest from Iain Lane in hope it succeeds on diff -Nru sphinx-1.3.6/debian/patches/correct_copyright_year_from_source_date_epoch.patch sphinx-1.3.6/debian/patches/correct_copyright_year_from_source_date_epoch.patch --- sphinx-1.3.6/debian/patches/correct_copyright_year_from_source_date_epoch.patch 1970-01-01 01:00:00.000000000 +0100 +++ sphinx-1.3.6/debian/patches/correct_copyright_year_from_source_date_epoch.patch 2016-04-13 14:36:48.000000000 +0200 @@ -0,0 +1,45 @@ +Description: Correct copyright year from SOURCE_DATE_EPOCH + If the environment variable SOURCE_DATE_EPOCH is set, use it to correct + uncoherent copyright years that are set using strftime, which don't honour + SOURCE_DATE_EPOCH. + This helps reproducibility of packages that build-depends on sphinx. +Author: Alexis Bienvenüe <p...@passoire.fr> + +Index: sphinx-1.3.6/sphinx/config.py +=================================================================== +--- sphinx-1.3.6.orig/sphinx/config.py ++++ sphinx-1.3.6/sphinx/config.py +@@ -10,14 +10,14 @@ + """ + + import re +-from os import path, environ ++from os import path, environ, getenv + import shlex + + from six import PY3, iteritems, string_types, binary_type, integer_types + + from sphinx.errors import ConfigError + from sphinx.locale import l_ +-from sphinx.util.osutil import make_filename, cd ++from sphinx.util.osutil import make_filename, cd, ustrftime + from sphinx.util.pycompat import execfile_ + + nonascii_re = re.compile(br'[\x80-\xff]') +@@ -286,6 +286,16 @@ class Config(object): + self.setup = config.get('setup', None) + self.extensions = config.get('extensions', []) + ++ # correct values of copyright year that are not coherent with ++ # the SOURCE_DATE_EPOCH environment variable: ++ source_date_epoch = getenv('SOURCE_DATE_EPOCH') ++ if source_date_epoch is not None: ++ for k in ['copyright','epub_copyright']: ++ if k in config: ++ config[k] = re.sub('^((\d{4}-)?)(\d{4})(?=[ ,])', ++ '\g<1>%s' % ustrftime('%Y'), ++ config[k]) ++ + def check_types(self, warn): + # check all values for deviation from the default value's type, since + # that can result in TypeErrors all over the place diff -Nru sphinx-1.3.6/debian/patches/series sphinx-1.3.6/debian/patches/series --- sphinx-1.3.6/debian/patches/series 2016-03-03 18:22:21.000000000 +0100 +++ sphinx-1.3.6/debian/patches/series 2016-04-13 14:02:26.000000000 +0200 @@ -7,3 +7,4 @@ reproducible_inventory.diff reproducible_js_locale.diff reproducible_searchindex.diff +correct_copyright_year_from_source_date_epoch.patch diff -Nru sphinx-1.3.6/debian/patches/source_date_epoch.diff sphinx-1.3.6/debian/patches/source_date_epoch.diff --- sphinx-1.3.6/debian/patches/source_date_epoch.diff 2016-03-03 18:22:21.000000000 +0100 +++ sphinx-1.3.6/debian/patches/source_date_epoch.diff 2016-04-13 10:03:43.000000000 +0200 @@ -11,10 +11,10 @@ sphinx/util/osutil.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) -diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py -index 70d5cf5..e1d29a9 100644 ---- a/sphinx/util/osutil.py -+++ b/sphinx/util/osutil.py +Index: sphinx-1.3.6/sphinx/util/osutil.py +=================================================================== +--- sphinx-1.3.6.orig/sphinx/util/osutil.py ++++ sphinx-1.3.6/sphinx/util/osutil.py @@ -151,15 +151,22 @@ no_fn_re = re.compile(r'[^a-zA-Z0-9_-]') def make_filename(string): return no_fn_re.sub('', string) or 'sphinx' @@ -42,3 +42,102 @@ # On Windows, time.strftime() and Unicode characters will raise UnicodeEncodeError. # http://bugs.python.org/issue8304 try: +Index: sphinx-1.3.6/sphinx/builders/epub.py +=================================================================== +--- sphinx-1.3.6.orig/sphinx/builders/epub.py ++++ sphinx-1.3.6/sphinx/builders/epub.py +@@ -29,7 +29,7 @@ from docutils import nodes + + from sphinx import addnodes + from sphinx.builders.html import StandaloneHTMLBuilder +-from sphinx.util.osutil import ensuredir, copyfile, EEXIST ++from sphinx.util.osutil import ensuredir, copyfile, EEXIST, ustrftime + from sphinx.util.smartypants import sphinx_smarty_pants as ssp + from sphinx.util.console import brown + +@@ -511,7 +511,7 @@ class EpubBuilder(StandaloneHTMLBuilder) + metadata['copyright'] = self.esc(self.config.epub_copyright) + metadata['scheme'] = self.esc(self.config.epub_scheme) + metadata['id'] = self.esc(self.config.epub_identifier) +- metadata['date'] = self.esc(time.strftime('%Y-%m-%d')) ++ metadata['date'] = self.esc(ustrftime('%Y-%m-%d')) + metadata['files'] = files + metadata['spine'] = spine + metadata['guide'] = guide +Index: sphinx-1.3.6/sphinx/builders/gettext.py +=================================================================== +--- sphinx-1.3.6.orig/sphinx/builders/gettext.py ++++ sphinx-1.3.6/sphinx/builders/gettext.py +@@ -11,7 +11,7 @@ + + from __future__ import unicode_literals + +-from os import path, walk ++from os import path, walk, getenv + from codecs import open + from time import time + from datetime import datetime, tzinfo, timedelta +@@ -130,7 +130,10 @@ class I18nBuilder(Builder): + timestamp = time() + tzdelta = datetime.fromtimestamp(timestamp) - \ + datetime.utcfromtimestamp(timestamp) +- ++source_date_epoch = getenv('SOURCE_DATE_EPOCH') ++if source_date_epoch is not None: ++ timestamp = float(source_date_epoch) ++ tzdelta = 0 + + class LocalTimeZone(tzinfo): + +Index: sphinx-1.3.6/sphinx/quickstart.py +=================================================================== +--- sphinx-1.3.6.orig/sphinx/quickstart.py ++++ sphinx-1.3.6/sphinx/quickstart.py +@@ -35,7 +35,7 @@ from six.moves.urllib.parse import quote + from docutils.utils import column_width + + from sphinx import __display_version__ +-from sphinx.util.osutil import make_filename ++from sphinx.util.osutil import make_filename, ustrftime + from sphinx.util.console import purple, bold, red, turquoise, \ + nocolor, color_terminal + from sphinx.util import texescape +@@ -1335,7 +1335,7 @@ def generate(d, overwrite=True, silent=F + d['extensions'] = '\n' + indent + extensions + ',\n' + else: + d['extensions'] = extensions +- d['copyright'] = time.strftime('%Y') + ', ' + d['author'] ++ d['copyright'] = ustrftime('%Y') + ', ' + d['author'] + d['author_texescaped'] = text_type(d['author']).\ + translate(texescape.tex_escape_map) + d['project_doc'] = d['project'] + ' Documentation' +Index: sphinx-1.3.6/tests/test_quickstart.py +=================================================================== +--- sphinx-1.3.6.orig/tests/test_quickstart.py ++++ sphinx-1.3.6/tests/test_quickstart.py +@@ -21,6 +21,7 @@ from sphinx import application + from sphinx import quickstart as qs + from sphinx.util.console import nocolor, coloron + from sphinx.util.pycompat import execfile_ ++from sphinx.util.osutil import ustrftime + + + warnfile = StringIO() +@@ -147,7 +148,7 @@ def test_quickstart_defaults(tempdir): + assert ns['source_suffix'] == '.rst' + assert ns['master_doc'] == 'index' + assert ns['project'] == 'Sphinx Test' +- assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y') ++ assert ns['copyright'] == '%s, Georg Brandl' % ustrftime('%Y') + assert ns['version'] == '0.1' + assert ns['release'] == '0.1' + assert ns['todo_include_todos'] is False +@@ -207,7 +208,7 @@ def test_quickstart_all_answers(tempdir) + assert ns['master_doc'] == 'contents' + assert ns['project'] == u'STASIâ¢' + assert ns['copyright'] == u'%s, Wolfgang Schäuble & G\'Beckstein' % \ +- time.strftime('%Y') ++ ustrftime('%Y') + assert ns['version'] == '2.0' + assert ns['release'] == '2.0.1' + assert ns['todo_include_todos'] is True
_______________________________________________ Reproducible-builds mailing list Reproducible-builds@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/reproducible-builds