Bug#759405: perl: make pod2man timestamps reproducible

Russ Allbery rra at debian.org
Sat Aug 30 22:14:47 UTC 2014


Niko Tyni <ntyni at debian.org> writes:

> I doubt any normal build system feeds STDIN to Pod::Man, but another
> case where the current time is used is when there are Debian patches to
> the source file. Quoting the dpkg-source(1) manual page:

>   The timestamp of all patched files is reset to the extraction time of
>   the source package (this avoids timestamp skews  leading  to  problems
>   when  autogenerated  files  are patched)

> I've filed #759404 against dpkg-dev about changing this, but in the
> meantime it would be nice to fix/work around this somehow. The best thing
> I've come up with is an environment variable (maybe POD2MAN_DATE?) that
> would override the date; changing build systems to pass the '--date'
> option to pod2man or its equivalents would be much more intrusive.

Since this option would be implemented in Pod::Man, rather than pod2man, I
went with POD_MAN_DATE instead.  This is now implemented.  I pushed a
change to the podlators Git repository,a nd it will be in the next
release.

Here's the full diff, although you'll need to extract the source change to
apply it to the podlators in Perl core since I'm also doing a bunch of
package restructuring and some coding style updates for the next release.

commit 8609def7289033134ca0bb0db60cd0411fdc4f3d
Author: Russ Allbery <rra at cpan.org>
Date:   Sat Aug 30 15:10:41 2014 -0700

    Support POD_MAN_DATE in Pod::Man for the left-hand footer
    
    Honor the environment variable POD_MAN_DATE and use its contents, if
    set, as the value of the left-hand footer if the date option is not
    set, overriding the timestamp of the input file.  This is primarily
    useful to ensure reproducible builds of the same output file given the
    same souce and Pod::Man version, even when file timestamps may not be
    consistent.  Thanks, Niko Tyni.

diff --git a/Changes b/Changes
index 9b7870c..2b752da 100644
--- a/Changes
+++ b/Changes
@@ -12,6 +12,13 @@ podlators 4.00 (unreleased)
     warnings.  Please report any unexpected or confusing warnings as bugs
     in the bug tracker.
 
+    [Pod::Man] Honor the environment variable POD_MAN_DATE and use its
+    contents, if set, as the value of the left-hand footer if the date
+    option is not set, overriding the timestamp of the input file.  This
+    is primarily useful to ensure reproducible builds of the same output
+    file given the same souce and Pod::Man version, even when file
+    timestamps may not be consistent.  Thanks, Niko Tyni.
+
     Fix documentation of the utf8 option to Pod::Man and Pod::Text, and
     the corresponding -u option to pod2man and pod2text, to reflect that
     Pod::Simple now autodetects Latin-1 and UTF-8 but warns.
diff --git a/THANKS b/THANKS
index a411c22..c8fa3d6 100644
--- a/THANKS
+++ b/THANKS
@@ -156,7 +156,8 @@ input and output in Perl.  This resolved several confusions, including a
 bad assumption about how non-breaking spaces should be handled.
 
 Niko Tyni, for lots of helpful bug reports and testing in combination with
-the Perl packages in Debian.
+the Perl packages in Debian, and for the proposal for POD_MAN_DATE to
+support reproducible builds.
 
 Jerry D. Hedden, for spelling fixes and pointing out differences in
 aspell's dictionary on different systems.
diff --git a/lib/Pod/Man.pm b/lib/Pod/Man.pm
index d292dc2..029cccb 100644
--- a/lib/Pod/Man.pm
+++ b/lib/Pod/Man.pm
@@ -877,25 +877,42 @@ sub devise_title {
 }
 
 # Determine the modification date and return that, properly formatted in ISO
-# format.  If we can't get the modification date of the input, instead use the
-# current time.  Pod::Simple returns a completely unuseful stringified file
-# handle as the source_filename for input from a file handle, so we have to
-# deal with that as well.
+# format.
+#
+# If POD_MAN_DATE is set, that overrides anything else.  This can be used for
+# reproducible generation of the same file even if the input file timestamps
+# are unpredictable or the POD coms from standard input.
+#
+# Otherwise, use the modification date of the input if we can stat it.  Be
+# aware that Pod::Simple returns the stringification of the file handle as
+# source_filename for input from a file handle, so we'll stat some random ref
+# string in that case.  If that fails, instead use the current time.
+#
+# $self - Pod::Man object, used to get the source file
+#
+# Returns: YYYY-MM-DD date suitable for the left-hand footer
 sub devise_date {
     my ($self) = @_;
+
+    # If POD_MAN_DATE is set, always use it.
+    if ($ENV{POD_MAN_DATE}) {
+        return $ENV{POD_MAN_DATE};
+    }
+
+    # Otherwise, get the input filename and try to stat it.  If that fails,
+    # use the current time.
     my $input = $self->source_filename;
     my $time;
     if ($input) {
-        $time = (stat $input)[9] || time;
+        $time = (stat($input))[9] || time();
     } else {
-        $time = time;
+        $time = time();
     }
 
-    # Can't use POSIX::strftime(), which uses Fcntl, because MakeMaker
-    # uses this and it has to work in the core which can't load dynamic
-    # libraries.
-    my ($year, $month, $day) = (localtime $time)[5,4,3];
-    return sprintf ("%04d-%02d-%02d", $year + 1900, $month + 1, $day);
+    # Can't use POSIX::strftime(), which uses Fcntl, because MakeMaker uses
+    # this and it has to work in the core which can't load dynamic libraries.
+    my ($year, $month, $day) = (localtime($time))[5,4,3];
+    return sprintf("%04d-%02d-%02d", $year + 1900, $month + 1, $day);
 }
 
 # Print out the preamble and the title.  The meaning of the arguments to .TH
@@ -1633,6 +1650,15 @@ argument.
 Sets the centered page header to use instead of "User Contributed Perl
 Documentation".
 
+=item date
+
+Sets the left-hand footer.  If this option is not set, the contents of the
+environment variable POD_MAN_DATE, if set, will be used.  Failing that,
+the modification date of the input file will be used, or the current time
+if stat() can't find that file (which will be the case if the input is
+from C<STDIN>).  If obtained from the file modification date or the
+current time, he date will be formatted as C<YYYY-MM-DD>.
+
 =item errors
 
 How to report errors.  C<die> says to throw an exception on any POD
@@ -1643,13 +1669,6 @@ POD errors entirely, as much as possible.
 
 The default is C<pod>.
 
-=item date
-
-Sets the left-hand footer.  By default, the modification date of the input
-file will be used, or the current date if stat() can't find that file (the
-case if the input is from C<STDIN>), and the date will be formatted as
-C<YYYY-MM-DD>.
-
 =item fixed
 
 The fixed-width font to use for verbatim text and code.  Defaults to
@@ -1811,6 +1830,20 @@ option was set to C<die>.
 
 =back
 
+=head1 ENVIRONMENT
+
+=over 4
+
+=item POD_MAN_DATE
+
+If set, this will be used as the value of the left-hand footer unless the
+C<date> option is explicitly set, overriding the timestamp of the input
+file or the current time.  This is primarily useful to ensure reproducible
+builds of the same output file given the same souce and Pod::Man version,
+even when file timestamps may not be consistent.
+
+=back
+
 =head1 BUGS
 
 Encoding handling assumes that PerlIO is available and does not work
diff --git a/t/man/devise-date.t b/t/man/devise-date.t
index 3cce9f5..c610dd9 100755
--- a/t/man/devise-date.t
+++ b/t/man/devise-date.t
@@ -1,15 +1,28 @@
-#!/usr/bin/perl -w
-
-# In order for MakeMaker to build in the core, nothing can use
-# Fcntl which includes POSIX.  devise_date()'s use of strftime()
-# was replaced.  This tests that it's identical.
+#!/usr/bin/perl
+#
+# In order for MakeMaker to build in the core, nothing can use Fcntl which
+# includes POSIX.  devise_date()'s use of strftime() was replaced.  This tests
+# that it's identical.  It also tests special handling of the POD_MAN_DATE
+# environment variable.
 
+use 5.006;
 use strict;
-
-use Test::More tests => 1;
+use warnings;
 
 use Pod::Man;
 use POSIX qw(strftime);
 
+use Test::More tests => 2;
+
+# Check that the results of device_date matches strftime.  There is no input
+# file name, so this will use the current time.
 my $parser = Pod::Man->new;
-is $parser->devise_date, strftime("%Y-%m-%d", localtime);
+is(
+    $parser->devise_date,
+    strftime('%Y-%m-%d', localtime()),
+    'devise_date matches strftime'
+);
+
+# Set the override environment variable and ensure that it's honored.
+local $ENV{POD_MAN_DATE} = '2014-01-01';
+is($parser->devise_date, '2014-01-01', 'devise_date honors POD_MAN_DATE');

-- 
Russ Allbery (rra at debian.org)               <http://www.eyrie.org/~eagle/>




More information about the Perl-maintainers mailing list