bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: SOURCE_DATE_EPOCH library code


From: Bruno Haible
Subject: Re: SOURCE_DATE_EPOCH library code
Date: Sun, 13 Dec 2020 12:59:05 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-193-generic; KDE/5.18.0; x86_64; ; )

Hi Miguel,

Moving this part off of the bugtracker <https://savannah.gnu.org/bugs/?59658>.
> > Can you submit a Gnulib module for SOURCE_DATE_EPOCH handling?
>
> I'm glad you ask.  I though about this while working on it, as any
> time/localtime call introduce that kind of reproducibility problems.  Reading
> gnulib's manual
> <https://www.gnu.org/software/gnulib/manual/html_node/Contributing-to-Gnulib.html>
> I see that at least one project has to use it.  GCC
> <https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/c-family/c-common.c;h=0b348aec77b8262306b37d1e4a5de490ca293e8e;hb=HEAD#l8557>
> has some code for it, which I'm using to discover missing points from my
> implementation: errno, long vs long long...
> 
> Nonetheless, I guess that a library interface should allow client code to
> identify issues with the variable as suggested by the specification, what do
> you think about this interface?
> 
> /* Read the environment variable SOURCE_DATE_EPOCH into the provided
>    time_t object.
> 
>    Return 0 when the value has been read successfully, or number of
>    characters left to read (up to INT_MAX) at SOURCE_DATE_EPOCH if the
>    number isn't well formed.
> 
>    Return -1 when the variable isn't defined or -2 when the variable
>    is defined but empty.
> 
>    See https://reproducible-builds.org/specs/source-date-epoch/  */
> int source_date_epoch_time (time_t *);
> 
> /* Like source_date_epoch_time but read into struct tm.  */
> int source_date_epoch_tm (struct tm *);
> 
> 
> It allows the client code to ignore any error like this:
> 
> if (source_date_epoch_time (&now) != 0)
>   /* oops: SOURCE_DATE_EPOCH is not there, perhaps call time (&now),
>      show a message, check errno...  */
> 
> 
> Or to handle them:
> 
> switch (source_date_epoch_time (&now))
> {
>   case -2:
>     /* Do the thing when it is defined but empty, fall through?  */
>   case -1:
>     /* Do the thing when it isn't defined.  */
>     break;
>   case 0:
>     /* Do the thing when it is defined and OK.  */
>     break;
>   default:
>     /* Exit with non-zero as suggested by the spec.  */
>     exit (1);
> }
> 
> 
> Also, I've noticed that the common idiom is to define TZ together with
> SOURCE_DATE_EPOCH, as gettext's copy of help2man
> <https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/man/help2man#n273>
> does, even though the spec says that it must be treated always as UTC.  If
> that assumption is made, the modifications to po_strftime can be removed and
> we can forget about any issue regarding the localtime/gmtime because they will
> return the same value.  If not, I suggest keeping the interface modification
> from the latest patch
> <https://savannah.gnu.org/bugs/download.php?file_id=50444>.

I can see two relevant documents regarding SOURCE_DATE_EPOCH:
The documentation <https://reproducible-builds.org/docs/source-date-epoch/> and
the specification <https://reproducible-builds.org/specs/source-date-epoch/>.

The specification says
  "A UNIX timestamp, defined as the number of seconds, excluding leap seconds,
   since 01 Jan 1970 00:00:00 UTC."
To me, it is thus clear that in the 'source_date_epoch_time' function no
timezone handling is involved.

Whereas for 'source_date_epoch_tm': The documentation of this function should
state whether it produces a 'struct tm' in local time or a 'struct tm' in
UTC time. Due to the existence of the functions localtime() and gmtime() in
ISO C, you cannot know a priori.

It is good to provide an 'int' as return code and let the application do the
error reporting.

Does this return code need to carry 4 different cases? The specification says:
  "... use a timestamp no later than the value of this variable."
  "If the value is malformed, the build process SHOULD exit ..."
To me, this sounds as if there are 3 different cases:
  - The value is provided and valid.
  - The value is provided and invalid.
  - The value is not provided.

When the value is defined to an empty value, it is invalid; that is my
reading of the specification and of the example code for C.
POSIX-defined environment variables (such as LANG) with an empty value are
considered equivalent to an absent value; this is because ages ago, shells
did not have an 'unset' command that could remove an environment variable
from the environment. But nowadays, this 'unset' command exists, and
therefore there is no need any more to treat an empty value like an absent
value (for things that are not specified by POSIX).

Bruno




reply via email to

[Prev in Thread] Current Thread [Next in Thread]