Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reproducible gem -> deb conversion #1360

Merged
merged 7 commits into from Jul 20, 2017

Conversation

dankegel
Copy link
Contributor

@dankegel dankegel commented Jun 27, 2017

Partial fix for #1232
Ready for review and merging.

It fetches the source epoch from the changelog for about a third of the gems I tried.

Native gems still have some randomness on Darwin, but I'm not going to worry about that;
docs/source/gem.rst mentions that it's only been verified to produce identical results on Linux.

The following test passes locally on ubuntu 16.04:

 mkdir run1
 ruby -Ilib bin/fpm -s gem -t deb --gem-stagingdir /tmp/gem1.tmp --source-date-epoch-from-changelog json
 mv *.deb run1

 mkdir run2
 ruby -Ilib bin/fpm -s gem -t deb --gem-stagingdir /tmp/gem1.tmp --source-date-epoch-from-changelog json
 mv *.deb run2

 cmp run1/*.deb run2/*.deb

@dankegel
Copy link
Contributor Author

Pfft. Also found a mac problem locally. will upload fixes once it's happy.

This is the first step towards supporting bit-for-bit identical
output files given identical inputs.

Alas, Apple's ar is not too good at reading gnu ar archives,
so always use ar_cmd to find ar.
…o support bit-for-bit reproducible gem -> deb conversion

In those cases where we can get the release date out of the changelog,
use it; otherwise fall back to the value given by SOURCE_DATE_EPOCH aka --source-date-epoch-default.

--gem-stagingdir is a bit of a kludge, only needed because no
compiler supports https://reproducible-builds.org/specs/build-path-prefix-map/ yet.
Could have been global option, but not sure any other package handler
invokes compilers?  Could hoist it up later.

Also:
- Defer initializing staging_path so subclasses can sneak in new value
- gem: remove build files
@dankegel
Copy link
Contributor Author

For what it's worth, I tried converting 51 gems I use, with commands like

ruby -Ilib bin/fpm --debug --gem-stagingdir /tmp/gem.tmp --source-date-epoch-from-changelog --source-date-epoch-default 123 -s gem -t deb -v 2.0.2 rest-client

Results: All 51 gems yielded bit-for-bit identical .deb's.

About a third of them had usable changelogs:

clamp-0.6.5 colorize-0.8.1 domain_name-0.5.20170404 eventmachine-1.2.0.1
fpm-1.3.3 hashdiff-0.3.2 http-cookie-1.0.3 http-1.0.4 json-1.8.3
nokogiri-1.5.10 parseconfig-1.0.8 rack_csrf-2.6.0 sinatra-1.4.7
term-ansicolor-1.3.2 tilt-2.0.2 unf_ext-0.0.7.4 uuid-2.3.8

Another few had changelogs, but without a recognizable date for this version:

addressable-2.5.0 backports-3.6.8 cabin-0.8.1 erubis-2.7.0 netrc-0.11.0
public_suffix-2.0.5 ruby-ldap-0.9.18 safe_yaml-1.0.4 thin-1.7.0 unf-0.1.4
webmock-2.3.2

No changelog found:

arr-pm-0.0.10 childprocess-0.5.9 crack-0.4.3 daemons-1.2.3
escape-0.0.4 ffi-1.9.10 http_parser.rb-0.6.0 kgio-2.10.0 macaddr-1.7.1
mime-types-data-3.2016.0521 mime-types-3.1.0 net-ldap-0.14.0 rack-1.6.4
rack-protection-1.5.3 rainbows-5.0.0 raindrops-0.16.0 rb-inotify-0.9.7
rest-client-2.0.2 sinatra-packrat-0.2.3 systemd-journal-1.2.3
systemu-2.6.5 tins-1.10.1 unicorn-5.0.1

Hmm, if only we could get the attention of the author of arr-pm to add a changelog :-)


# Override parent method
def staging_path(path=nil)
@gem_staging_path ||= attributes[:gem_stagingdir] || Stud::Temporary.directory("package-#{type}-staging")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long-term I would prefer a simpler user experience for deterministic builds (perhaps a single flag --deterministic-build) that would make these kinds of decisions for the user. For now, this is good :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, yeah... but long-term this option won't be needed (once compilers obey https://reproducible-builds.org/specs/build-path-prefix-map/ ), so if we're going to have an intermediate workaround, let's make it simple, transparent, and scary so nobody uses it by accident.

def ar_cmd
return @@ar_cmd if defined? @@ar_cmd

@@ar_cmd_deterministic = FALSE
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL Ruby provides a constant FALSE that means false. This should probably be lowercase false (for style) but there is no negative impact to the user, so it's cool.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ruby 2.4 warns about this constant, so I'll remove it after merging:

../home/jls/projects/fpm/lib/fpm/util.rb:284: warning: constant ::FALSE is deprecated
/home/jls/projects/fpm/lib/fpm/util.rb:301: warning: constant ::TRUE is deprecated
/home/jls/projects/fpm/lib/fpm/util.rb:241: warning: constant ::FALSE is deprecated
/home/jls/projects/fpm/lib/fpm/util.rb:255: warning: constant ::TRUE is deprecated

@jordansissel
Copy link
Owner

Did a light review and ran the test suite. Tests passing and overall the code is good. Thank you for writing docs :)

@jordansissel jordansissel merged commit 14c4819 into jordansissel:master Jul 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants