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 <mike@mikemcquaid.com>
This commit is contained in:
Mike McQuaid 2015-12-15 14:21:27 +00:00
parent e5ba31fcdc
commit 214c865167
2 changed files with 28 additions and 1 deletions

View File

@ -174,6 +174,9 @@ module Homebrew
filename = Bottle::Filename.create(f, bottle_tag, bottle_revision) filename = Bottle::Filename.create(f, bottle_tag, bottle_revision)
bottle_path = Pathname.pwd/filename bottle_path = Pathname.pwd/filename
tar_filename = filename.to_s.sub(/.gz$/, "")
tar_path = Pathname.pwd/tar_filename
prefix = HOMEBREW_PREFIX.to_s prefix = HOMEBREW_PREFIX.to_s
cellar = HOMEBREW_CELLAR.to_s cellar = HOMEBREW_CELLAR.to_s
@ -183,7 +186,13 @@ module Homebrew
relocatable = false relocatable = false
skip_relocation = false skip_relocation = false
formula_source_time = f.stable.stage do
Pathname.pwd.to_enum(:find).map(&:mtime).max
end
keg.lock do keg.lock do
original_tab = nil
begin begin
keg.relocate_install_names prefix, Keg::PREFIX_PLACEHOLDER, keg.relocate_install_names prefix, Keg::PREFIX_PLACEHOLDER,
cellar, Keg::CELLAR_PLACEHOLDER cellar, Keg::CELLAR_PLACEHOLDER
@ -192,10 +201,25 @@ module Homebrew
keg.delete_pyc_files! 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 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 # Use gzip, faster to compress than bzip2, faster to uncompress than bzip2
# or an uncompressed tarball (and more bandwidth friendly). # 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 end
if bottle_path.size > 1*1024*1024 if bottle_path.size > 1*1024*1024
@ -222,6 +246,7 @@ module Homebrew
raise raise
ensure ensure
ignore_interrupts do ignore_interrupts do
original_tab.write
keg.relocate_install_names Keg::PREFIX_PLACEHOLDER, prefix, keg.relocate_install_names Keg::PREFIX_PLACEHOLDER, prefix,
Keg::CELLAR_PLACEHOLDER, cellar Keg::CELLAR_PLACEHOLDER, cellar
end end

View File

@ -741,6 +741,8 @@ class FormulaInstaller
tab.tap = formula.tap tab.tap = formula.tap
tab.poured_from_bottle = true tab.poured_from_bottle = true
tab.time = Time.now.to_i
tab.head = Homebrew.git_head
tab.write tab.write
end end