On 29/12/15 17:18, Ricardo Wurmus wrote:
Ben Woodcroft <b.woodcr...@uq.edu.au> writes:

Unfortunately none of these builds are reproducible because rubygems in
Guix generally aren't. For one, this is because .gem files are archives
whose contents are timestamped.
I found the same problem with Java stuff.  “.jar” files are archives of
the generated “.class” files and they contain an automatically generated
manifest.  To fix this in a build system I’m planning to unpack all
files from the “.jar”, then “touch -d @0” each file, and then repack
with “jar” without creating a new manifest.

So far “touch”-ing every class file after compilation and leaving off
the manifest at jar creation time has shown that “jar” archives can be
made reproducible.

“gem” archives are really just slightly modified “tar” archives, aren’t
they?  Maybe we could add a phase to the ruby-build-system — or modify
the “build” phase, which unpacks and rebuilds the “.gem” archive.
Yep, they are just tar files. But since it is just a cache, can we just delete the gem file as per attached? Too ham-fisted?

Of the 104 gems in my checkout of gnu/packages/ruby.scm, only 14 are now not reproducible (as opposed to 104 beforehand I think). None seem to fail to build the traditional way. I believe the remaining offendors are not reproducible because they compile native extensions leading to further timestamp issues. I think after this we are OK to test pure Ruby packages for reproducibility.

The offendors:
ruby-byebug
ruby-eventmachine
ruby-ffi
ruby-json
ruby-libxml
ruby-nokogiri
ruby-nokogumbo
ruby-ox
ruby-pg
ruby-rack
ruby-redcarpet
ruby-redcloth
ruby-rjb
ruby-unf-ext

Another case where Ruby was easier than Java? :P

Thanks,
ben
>From 3568c651f6035fefd35f42917710eb5a1bf72bab Mon Sep 17 00:00:00 2001
From: Ben Woodcroft <donttrust...@gmail.com>
Date: Wed, 30 Dec 2015 10:27:33 +1000
Subject: [PATCH] build: ruby: Remove cached gem after install.

The .gem file stored in GEM_HOME after install is both redundant and an
archive that stores timestamped files which makes builds non-deterministic. So
delete it after 'gem install'.

* guix/build/ruby-build-system.scm (install): Remove cached gem after install.

will be ignored, and an empty message aborts the commit.  # On branch
ruby-deterministic # Changes to be committed: # modified:
guix/build/ruby-build-system.scm # # Untracked files: # guix_gets #
---
 guix/build/ruby-build-system.scm | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm
index 2685da1..52d7e96 100644
--- a/guix/build/ruby-build-system.scm
+++ b/guix/build/ruby-build-system.scm
@@ -115,15 +115,19 @@ GEM-FLAGS are passed to the 'gem' invokation, if present."
                                          (assoc-ref inputs "ruby"))
                            1))
          (out (assoc-ref outputs "out"))
-         (gem-home (string-append out "/lib/ruby/gems/" ruby-version ".0")))
-
+         (gem-home (string-append out "/lib/ruby/gems/" ruby-version ".0"))
+         (gem-name (first-matching-file "\\.gem$")))
     (setenv "GEM_HOME" gem-home)
     (mkdir-p gem-home)
-    (zero? (apply system* "gem" "install" (first-matching-file "\\.gem$")
-                  "--local" "--ignore-dependencies"
-                  ;; Executables should go into /bin, not /lib/ruby/gems.
-                  "--bindir" (string-append out "/bin")
-                  gem-flags))))
+    (apply system* "gem" "install" gem-name
+           "--local" "--ignore-dependencies"
+           ;; Executables should go into /bin, not /lib/ruby/gems.
+           "--bindir" (string-append out "/bin")
+           gem-flags)
+    ;; Remove the cached gem file as this is unnecessary and contains
+    ;; timestamped files rendering builds not reproducible.
+    (delete-file (string-append gem-home "/cache/" gem-name))
+    #t))
 
 (define %standard-phases
   (modify-phases gnu:%standard-phases
-- 
2.6.3

Reply via email to