[PATCH] Please make the output of cache files reproducible

Chris Lamb <[email protected]>
Newsgroups gmane.comp.fonts.fontconfig
Message-ID <1496970669.1851963.1003601632.285105AB@webmail.messagingengine.com>
Hi,

Whilst working on the Reproducible Builds[0] effort, we noticed that
fontconfig — in its usual usage — generates un-reproducible cache files.

This is due to it using the timestamps of each directory in the
"checksum" member of the _FcCache struct. This is so that it can identify
which cache files remain valid and/or require regeneration.

Whilst we could zero-out the checksum, we would actually need it still
function correctly. Therefore, I've attached a patch that adds an option
to list all the configured font directories; that way, distributions,
etc. can modify the mtimes of these files in advance

For example, I'm about to propose the following to Debian's fontconfig
"postinst" script:

  if [ -n "$SOURCE_DATE_EPOCH" ]; then
    fc-cache -s --list-dirs | \
      xargs -I{} find {} -type d -follow -newermt "@$SOURCE_DATE_EPOCH" -print0 2>/dev/null | \
      xargs -0r touch --date="@$SOURCE_DATE_EPOCH"
  fi

… and then we make the usual calls to, for example:

  $ fc-cache -s -f -v


(This work was sponsored by Tails[1].)


 [0] https://reproducible-builds.org/
 [1] https://tails.boum.org/


Regards,

-- 
      ,''`.
     : :'  :     Chris Lamb
     `. `'`      [email protected] / chris-lamb.co.uk
       `-

_______________________________________________
Fontconfig mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/fontconfig
reproducible.diff.txt (text/plain, 5.7 KB)
diff -urNad fontconfig-2.11.0.orig/fc-cache/fc-cache.1 fontconfig-2.11.0/fc-cache/fc-cache.1
--- fontconfig-2.11.0.orig/fc-cache/fc-cache.1	2017-05-26 16:30:36.585878534 +0100
+++ fontconfig-2.11.0/fc-cache/fc-cache.1	2017-05-26 18:12:58.022734653 +0100
@@ -4,7 +4,7 @@
 fc-cache \- build font information cache files
 .SH SYNOPSIS
 .sp
-\fBfc-cache\fR [ \fB-frsvVh\fR ]  [ \fB--force\fR ]  [ \fB--really-force\fR ]  [ \fB--system-only\fR ]  [ \fB--verbose\fR ]  [ \fB--version\fR ]  [ \fB--help\fR ]  [ \fB\fIdir\fB\fR\fI...\fR ] 
+\fBfc-cache\fR [ \fB-frsvVh\fR ]  [ \fB--force\fR ]  [ \fB--really-force\fR ]  [ \fB--system-only\fR ]  [ \fB--list-dirs\fR ]  [ \fB--verbose\fR ]  [ \fB--version\fR ]  [ \fB--help\fR ]  [ \fB\fIdir\fB\fR\fI...\fR ] 
 .SH "DESCRIPTION"
 .PP
 \fBfc-cache\fR scans the font directories on
@@ -39,6 +39,9 @@
 Only scan system-wide directories, omitting the places
 located in the user's home directory.
 .TP
+\fB-l\fR
+Only list directories, don't regenerate anything.
+.TP
 \fB-v\fR
 Display status information while busy.
 .TP
diff -urNad fontconfig-2.11.0.orig/fc-cache/fc-cache.c fontconfig-2.11.0/fc-cache/fc-cache.c
--- fontconfig-2.11.0.orig/fc-cache/fc-cache.c	2017-05-26 16:30:36.585878534 +0100
+++ fontconfig-2.11.0/fc-cache/fc-cache.c	2017-05-26 18:13:33.810917986 +0100
@@ -69,6 +69,7 @@
     {"really-force", 0, 0, 'r'},
     {"sysroot", 0, 0, 'y'},
     {"system-only", 0, 0, 's'},
+    {"list-dirs", 0, 0, 'l'},
     {"version", 0, 0, 'V'},
     {"verbose", 0, 0, 'v'},
     {"help", 0, 0, 'h'},
@@ -86,10 +87,10 @@
 {
     FILE *file = error ? stderr : stdout;
 #if HAVE_GETOPT_LONG
-    fprintf (file, "usage: %s [-frsvVh] [-y SYSROOT] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n",
+    fprintf (file, "usage: %s [-frsvVh] [-y SYSROOT] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--list-dirs] [--verbose] [--version] [--help] [dirs]\n",
 	     program);
 #else
-    fprintf (file, "usage: %s [-frsvVh] [-y SYSROOT] [dirs]\n",
+    fprintf (file, "usage: %s [-frslvVh] [-y SYSROOT] [dirs]\n",
 	     program);
 #endif
     fprintf (file, "Build font information caches in [dirs]\n"
@@ -100,6 +101,7 @@
     fprintf (file, "  -r, --really-force       erase all existing caches, then rescan\n");
     fprintf (file, "  -s, --system-only        scan system-wide directories only\n");
     fprintf (file, "  -y, --sysroot=SYSROOT    prepend SYSROOT to all paths for scanning\n");
+    fprintf (file, "  -l, --list-dirs          list directories only\n");
     fprintf (file, "  -v, --verbose            display status information while busy\n");
     fprintf (file, "  -V, --version            display font config version and exit\n");
     fprintf (file, "  -h, --help               display this help and exit\n");
@@ -108,6 +110,7 @@
     fprintf (file, "  -r,   (really force) erase all existing caches, then rescan\n");
     fprintf (file, "  -s         (system)  scan system-wide directories only\n");
     fprintf (file, "  -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n");
+    fprintf (file, "  -l         (list-dirs) list directories only\n");
     fprintf (file, "  -v         (verbose) display status information while busy\n");
     fprintf (file, "  -V         (version) display font config version and exit\n");
     fprintf (file, "  -h         (help)    display this help and exit\n");
@@ -277,18 +280,20 @@
     FcBool	force = FcFalse;
     FcBool	really_force = FcFalse;
     FcBool	systemOnly = FcFalse;
+    FcBool	listDirs = FcFalse;
     FcConfig	*config;
     FcChar8     *sysroot = NULL;
+    FcChar8     *dir;
     int		i;
     int		changed;
-    int		ret;
+    int		ret = 0;
 #if HAVE_GETOPT_LONG || HAVE_GETOPT
     int		c;
 
 #if HAVE_GETOPT_LONG
-    while ((c = getopt_long (argc, argv, "frsy:Vvh", longopts, NULL)) != -1)
+    while ((c = getopt_long (argc, argv, "frsly:Vvh", longopts, NULL)) != -1)
 #else
-    while ((c = getopt (argc, argv, "frsy:Vvh")) != -1)
+    while ((c = getopt (argc, argv, "frsly:Vvh")) != -1)
 #endif
     {
 	switch (c) {
@@ -304,6 +309,9 @@
 	case 'y':
 	    sysroot = FcStrCopy ((const FcChar8 *)optarg);
 	    break;
+	case 'l':
+	    listDirs = FcTrue;
+	    break;
 	case 'V':
 	    fprintf (stderr, "fontconfig version %d.%d.%d\n", 
 		     FC_MAJOR, FC_MINOR, FC_REVISION);
@@ -365,6 +373,13 @@
     else
 	list = FcConfigGetConfigDirs (config);
 
+    if (listDirs)
+    {
+	while ((dir = FcStrListNext (list)))
+	    printf ("%s\n", dir);
+	goto done;
+    }
+
     if ((processed_dirs = FcStrSetCreate()) == NULL) {
 	fprintf(stderr, "Cannot malloc\n");
 	return 1;
@@ -388,6 +403,7 @@
 
     cleanCacheDirectories (config, verbose);
 
+done:
     FcConfigDestroy (config);
     FcFini ();
     /* 
diff -urNad fontconfig-2.11.0.orig/fc-cache/fc-cache.sgml fontconfig-2.11.0/fc-cache/fc-cache.sgml
--- fontconfig-2.11.0.orig/fc-cache/fc-cache.sgml	2017-05-26 16:30:36.585878534 +0100
+++ fontconfig-2.11.0/fc-cache/fc-cache.sgml	2017-05-26 18:10:26.789976370 +0100
@@ -67,6 +67,7 @@
       <arg><option>--force</option></arg>
       <arg><option>--really-force</option></arg>
       <arg><option>--system-only</option></arg>
+      <arg><option>--list-dirs</option></arg>
       <arg><option>--verbose</option></arg>
       <arg><option>--version</option></arg>
       <arg><option>--help</option></arg>
@@ -129,6 +130,14 @@
         </listitem>
       </varlistentry>
       <varlistentry>
+        <term><option>-l</option>
+          <option>--list-dirs</option>
+        </term>
+        <listitem>
+	  <para>Only list directories, don't regenerate anything.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><option>-v</option>
           <option>--verbose</option>
         </term>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.