From 214c865167cb11c05841aef9d3ff25399e7f6b73 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Tue, 15 Dec 2015 14:21:27 +0000 Subject: [PATCH] bottle: make bottle checksums reproducible. I've set all the variable data to versions that are dependent on the latest source file date and various modification dates also to the latest source file date. With this if you rerun `brew bottle` multiple times in a row you will see the same checksum even if you have `brew reinstall`ed (as long as upstream does not hardcode e.g. the build date). I debugged this with diffoscope and worked on this as part of the Athens 2015 reproducible builds workshop: https://reproducible-builds.org/events/athens2015/ Closes Homebrew/homebrew#46587. Signed-off-by: Mike McQuaid --- Library/Homebrew/cmd/bottle.rb | 27 ++++++++++++++++++++++++++- Library/Homebrew/formula_installer.rb | 2 ++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/cmd/bottle.rb b/Library/Homebrew/cmd/bottle.rb index a543000bc7..f642d458d9 100644 --- a/Library/Homebrew/cmd/bottle.rb +++ b/Library/Homebrew/cmd/bottle.rb @@ -174,6 +174,9 @@ module Homebrew filename = Bottle::Filename.create(f, bottle_tag, bottle_revision) bottle_path = Pathname.pwd/filename + tar_filename = filename.to_s.sub(/.gz$/, "") + tar_path = Pathname.pwd/tar_filename + prefix = HOMEBREW_PREFIX.to_s cellar = HOMEBREW_CELLAR.to_s @@ -183,7 +186,13 @@ module Homebrew relocatable = false skip_relocation = false + formula_source_time = f.stable.stage do + Pathname.pwd.to_enum(:find).map(&:mtime).max + end + keg.lock do + original_tab = nil + begin keg.relocate_install_names prefix, Keg::PREFIX_PLACEHOLDER, cellar, Keg::CELLAR_PLACEHOLDER @@ -192,10 +201,25 @@ module Homebrew keg.delete_pyc_files! + tab = Tab.for_keg(keg) + original_tab = tab.dup + empty_tab = Tab.empty + tab["poured_from_bottle"] = empty_tab["poured_from_bottle"] + tab["HEAD"] = empty_tab["HEAD"] + tab["time"] = empty_tab["time"] + tab.write + + keg.find {|k| File.utime(File.atime(k), formula_source_time, k) } + cd cellar do + safe_system "tar", "cf", tar_path, "#{f.name}/#{f.pkg_version}" + File.utime(File.atime(tar_path), formula_source_time, tar_path) + relocatable_tar_path = "#{f}-bottle.tar" + mv tar_path, relocatable_tar_path # Use gzip, faster to compress than bzip2, faster to uncompress than bzip2 # or an uncompressed tarball (and more bandwidth friendly). - safe_system "tar", "czf", bottle_path, "#{f.name}/#{f.pkg_version}" + safe_system "gzip", "-f", relocatable_tar_path + mv "#{relocatable_tar_path}.gz", bottle_path end if bottle_path.size > 1*1024*1024 @@ -222,6 +246,7 @@ module Homebrew raise ensure ignore_interrupts do + original_tab.write keg.relocate_install_names Keg::PREFIX_PLACEHOLDER, prefix, Keg::CELLAR_PLACEHOLDER, cellar end diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 0a483201f1..8fae101372 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -741,6 +741,8 @@ class FormulaInstaller tab.tap = formula.tap tab.poured_from_bottle = true + tab.time = Time.now.to_i + tab.head = Homebrew.git_head tab.write end