--- Begin Message ---
Source: sphinx
Version: 1.3.6-2
Severity: wishlist
Tags: patch upstream
User: [email protected]
Usertags: toolchain
X-Debbugs-Cc: [email protected]
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 <[email protected]> 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 <[email protected]>
+
+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
--- End Message ---