Skip to content

Commit

Permalink
Reproducible gem builds on jruby
Browse files Browse the repository at this point in the history
  • Loading branch information
segiddins committed Jul 17, 2024
1 parent 2d101aa commit 451569d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@

# rspec failure tracking
*.rspec_status

/build_gem/
34 changes: 28 additions & 6 deletions spec/gem_server_conformance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,43 @@
io.binmode
package = Gem::Package.new(io)
actual = []

presence = proc do |x|
x if x && !x.empty?
end

dump_tar = proc do |tar_io, into = actual|
Gem::Package::TarReader.new(tar_io) do |gem|
gem.each do |entry|
body = entry.read
body = Zlib.gunzip(body) if entry.full_name.end_with?(".gz")
extra = nil
if entry.full_name.end_with?(".gz")
extra = Zlib::GzipReader.wrap(StringIO.new(body)) do |gz|
magic, compression_method, flags, mtime, compression, os_id = body.unpack("H4ccVcC")
{
magic: magic, compression_method: compression_method, flags: flags, mtime: mtime,
compression: compression, os_id: os_id, comment: presence[gz.comment], crc: gz.crc,
orig_name: presence[gz.orig_name]
}.compact
end
body = Zlib.gunzip(body)
end
body = dump_tar[StringIO.new(body), []] if entry.full_name.end_with?(".tar.gz")

into << {
header: entry.header.instance_variables.to_h do |ivar|
[ivar.to_s.tr("@", "").to_sym, entry.header.instance_variable_get(ivar)]
end,
body: body
}
body: body,
extra: extra
}.compact
end
end
into
end
package.gem.with_read_io(&dump_tar)
expected_gz_extra = { compression: 2, compression_method: 8, crc: 0, flags: 0, magic: "1f8b", mtime: 0,
os_id: 3 }
expect(actual).to eq(
[{ body: <<~YAML,
--- !ruby/object:Gem::Specification
Expand Down Expand Up @@ -142,7 +161,8 @@
typeflag: "0",
uid: 0,
uname: "wheel",
version: 0 } },
version: 0 },
extra: expected_gz_extra },
{ body: [],
header: { checksum: 5834,
devmajor: 0,
Expand All @@ -160,7 +180,8 @@
typeflag: "0",
uid: 0,
uname: "wheel",
version: 0 } },
version: 0 },
extra: expected_gz_extra },
{ body: <<~YAML,
---
SHA256:
Expand All @@ -186,7 +207,8 @@
typeflag: "0",
uid: 0,
uname: "wheel",
version: 0 } }]
version: 0 },
extra: expected_gz_extra }]
)
end

Expand Down
35 changes: 35 additions & 0 deletions spec/support/request_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,34 @@ def encode_with(coder)
end
end

module PackageGzipToConsistentOS
class IOWrapper < SimpleDelegator
def write(str)
str[9] = "\x03".b if str.size == 10 && str.start_with?("\x1f\x8b".b)
super
end
end

def gzip_to(io, &blk)
super(IOWrapper.new(io), &blk)
end
end

::Gem::Dependency.class_eval do
if Gem::Dependency.method_defined?(:to_yaml_properties)
prepend(
Module.new do
def to_yaml_properties
expected = %i[@name @requirement @type @prerelease @version_requirements]
actual = super

(expected & actual) + (actual - expected)
end
end
)
end
end

def build_gem(name, version, platform: nil)
spec = Gem::Specification.new do |s|
s.name = name
Expand All @@ -40,10 +68,17 @@ def build_gem(name, version, platform: nil)
package = Gem::Package.new(StringIO.new.binmode)
package.build_time = Time.utc(1970)
package.spec = spec
package.singleton_class.prepend(PackageGzipToConsistentOS)
package.gem.singleton_class.send(:define_method, :path) { "" }

package.build

if ENV["DUMP_BUILD_GEM"]
tmp = "build_gem/#{RUBY_ENGINE}/rubygems-#{Gem::VERSION}/#{@time}"
FileUtils.mkdir_p(tmp)
File.binwrite("#{tmp}/#{spec.full_name}.gem", package.gem.io.string)
end

MockGem.new(
name: name,
version: spec.version,
Expand Down

0 comments on commit 451569d

Please sign in to comment.