Note that using this option will lead to an error if the resulting file
would not entirely be in ASCII.
+@item --no-git
+@opindex --no-git@r{, @code{xgettext} option}
+Don't use the @code{git} program
+to produce a reproducible @samp{POT-Creation-Date} field in the output.
+
+Use this option, for speed, if
+your project has a very long @code{Git} history
+(hundreds of thousands of commits)
+or you are specifying thousands of input files.
+
+By default, @code{xgettext} determines the @samp{POT-Creation-Date} as
+the maximum version-controlled modification time
+among all the given input files.
+With this option, you can specify that it should instead use
+the maximum modification time (time stamp on disk)
+among all the given input files.
+
+By ``version control'', here we mean the @code{Git} version control system.
+
@item --copyright-holder=@var{string}
@opindex --copyright-holder@r{, @code{xgettext} option}
Set the copyright holder in the output. @var{string} should be the
#include "msgl-ascii.h"
#include "msgl-ofn.h"
#include "xg-check.h"
+#include "stat-time.h"
#include "vc-mtime.h"
#include "po-time.h"
#include "msgl-header.h"
/* If nonzero omit header with information about this run. */
int xgettext_omit_header;
+/* If nonzero, don't use 'git' to compute a reproducible POT-Creation-Date. */
+static int xgettext_no_git;
+
/* Be more verbose. */
int verbose = 0;
{ "msgstr-prefix", optional_argument, NULL, 'm' },
{ "msgstr-suffix", optional_argument, NULL, 'M' },
{ "no-escape", no_argument, NULL, 'e' },
+ { "no-git", no_argument, NULL, CHAR_MAX + 23 },
{ "no-location", no_argument, NULL, CHAR_MAX + 16 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 4 },
{ "omit-header", no_argument, &xgettext_omit_header, 1 },
string_list_append (&files_for_vc_mtime, optarg);
break;
+ case CHAR_MAX + 23: /* --no-git */
+ xgettext_no_git = true;
+ break;
+
default:
usage (EXIT_FAILURE);
/* NOTREACHED */
printf (_("\
--omit-header don't write header with 'msgid \"\"' entry\n"));
printf (_("\
+ --no-git don't use the git program to produce a\n\
+ reproducible 'POT-Creation-Date' field in the\n\
+ output.\n"));
+ printf (_("\
--copyright-holder=STRING set copyright holder in output\n"));
printf (_("\
--foreign-user omit FSF copyright in output for foreign user\n"));
return mp;
}
+/* Accumulating mtimes. */
+struct accumulator
+{
+ bool has_some_mtimes;
+ struct timespec max_of_mtimes;
+};
+
+static void
+accumulate (struct accumulator *accu, struct timespec mtime)
+{
+ if (accu->has_some_mtimes)
+ {
+ /* Compute the maximum of accu->max_of_mtimes and mtime. */
+ if (accu->max_of_mtimes.tv_sec < mtime.tv_sec
+ || (accu->max_of_mtimes.tv_sec == mtime.tv_sec
+ && accu->max_of_mtimes.tv_nsec < mtime.tv_nsec))
+ accu->max_of_mtimes = mtime;
+ }
+ else
+ {
+ accu->max_of_mtimes = mtime;
+ accu->has_some_mtimes = true;
+ }
+}
+
+static int
+max_mtime_without_git (struct timespec *max_of_mtimes,
+ size_t nfiles, const char * const *filenames)
+{
+ if (nfiles == 0)
+ /* Invalid argument. */
+ abort ();
+
+ struct accumulator accu = { false };
+
+ /* Always use the file's time stamp. */
+ for (size_t n = 0; n < nfiles; n++)
+ {
+ struct stat statbuf;
+ if (stat (filenames[n], &statbuf) < 0)
+ return -1;
+
+ struct timespec mtime = get_stat_mtime (&statbuf);
+ accumulate (&accu, mtime);
+ }
+
+ /* Since nfiles > 0, we must have accumulated at least one mtime. */
+ if (!accu.has_some_mtimes)
+ abort ();
+ *max_of_mtimes = accu.max_of_mtimes;
+ return 0;
+}
+
static void
finalize_header (msgdomain_list_ty *mdlp)
{
time_t stamp;
struct timespec max_of_mtimes;
if (files_for_vc_mtime.nitems > 0
- && max_vc_mtime (&max_of_mtimes,
- files_for_vc_mtime.nitems, files_for_vc_mtime.item)
+ && (xgettext_no_git ? max_mtime_without_git : max_vc_mtime)
+ (&max_of_mtimes, files_for_vc_mtime.nitems, files_for_vc_mtime.item)
== 0)
/* Use the maximum of the encountered mtimes. */
stamp = max_of_mtimes.tv_sec;