Skip to content

Commit c8b9577

Browse files
committed
Refactor gem build
1 parent fe69232 commit c8b9577

9 files changed

Lines changed: 124 additions & 128 deletions

File tree

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
working-directory: gem
2727
steps:
2828
# Set up
29-
- uses: actions/checkout@v4
29+
- uses: actions/checkout@v5
3030
- name: Set up Ruby
3131
uses: ruby/setup-ruby@v1
3232
with:

gem/Rakefile

Lines changed: 1 addition & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,101 +2,11 @@
22

33
require 'bundler/gem_tasks'
44
require 'rspec/core/rake_task'
5-
require 'rubygems/package_task'
6-
require 'open-uri'
7-
require 'digest'
8-
9-
RSpec::Core::RakeTask.new(:spec)
10-
115
require 'rubocop/rake_task'
126

7+
RSpec::Core::RakeTask.new(:spec)
138
RuboCop::RakeTask.new
149

1510
task default: %i[prepare_build spec rubocop]
16-
17-
require_relative 'lib/triangulum/bun'
18-
19-
TRIANGULUM_GEMSPEC = Bundler.load_gemspec('triangulum.gemspec')
20-
2111
task prepare_build: %i[download build:entrypoints]
22-
2312
task package: %i[clobber prepare_build]
24-
25-
desc 'Clean downloaded bun binaries'
26-
task 'clobber:bun' do
27-
Triangulum::Bun::NATIVE_PLATFORMS.each_key do |platform|
28-
bun_path = File.join('exe', platform, 'bun')
29-
rm bun_path if File.exist?(bun_path)
30-
end
31-
end
32-
33-
task clobber: %i[clobber:bun]
34-
35-
exepaths = []
36-
37-
Triangulum::Bun::NATIVE_PLATFORMS.each do |platform, (zip_filename, expected_checksum)|
38-
TRIANGULUM_GEMSPEC.dup.tap do |gemspec|
39-
exedir = File.join('exe', platform)
40-
exepath = File.join(exedir, 'bun')
41-
42-
exepaths << exepath
43-
44-
gemspec.platform = platform
45-
gemspec.files += [exepath]
46-
47-
gem_path = Gem::PackageTask.new(gemspec).define
48-
desc "Build the #{platform} gem"
49-
task "gem:#{platform}" => [gem_path]
50-
51-
directory exedir
52-
file exepath => [exedir] do
53-
url = Triangulum::Bun.download_url(zip_filename)
54-
warn "Downloading #{exepath} from #{url} ..."
55-
56-
URI.open(url) do |remote| # rubocop:disable Security/Open
57-
zip_data = remote.read
58-
59-
actual_checksum = Digest::SHA256.hexdigest(zip_data)
60-
unless actual_checksum == expected_checksum
61-
raise "Checksum mismatch for #{zip_filename}: expected #{expected_checksum}, got #{actual_checksum}"
62-
end
63-
64-
# Bun zips contain a directory with the binary inside
65-
require 'zip'
66-
Zip::File.open_buffer(zip_data) do |zip|
67-
bun_entry = zip.find { |e| File.basename(e.name) == 'bun' }
68-
raise "bun binary not found in #{zip_filename}" unless bun_entry
69-
70-
File.binwrite(exepath, bun_entry.get_input_stream.read)
71-
end
72-
end
73-
74-
FileUtils.chmod(0o755, exepath, verbose: true)
75-
end
76-
end
77-
end
78-
79-
desc 'Download all bun binaries'
80-
task download: exepaths
81-
82-
desc 'Bundle the TypeScript entrypoints into single JS files'
83-
task 'build:entrypoints' do
84-
rm_rf 'lib/triangulum/js'
85-
directory 'lib/triangulum/js'
86-
87-
entrypoints = %w[single-validation]
88-
89-
entrypoints.each do |entrypoint|
90-
entrypoint_src = File.expand_path("../entrypoint/#{entrypoint}.ts", __dir__)
91-
entrypoint_dst = File.expand_path("lib/triangulum/js/#{entrypoint}.js", __dir__)
92-
93-
sh 'bun', 'build', entrypoint_src, '--outfile', entrypoint_dst, '--target', 'bun'
94-
end
95-
end
96-
97-
desc 'Push all platform gems to RubyGems'
98-
task 'push:all' do
99-
Dir['pkg/*.gem'].each do |gem_file|
100-
sh 'gem', 'push', gem_file
101-
end
102-
end

gem/lib/triangulum/bun.rb

Lines changed: 0 additions & 24 deletions
This file was deleted.

gem/lib/triangulum/validation.rb

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ class Validation
77
class TriangulumFailed < Triangulum::Error
88
end
99

10-
Result = Struct.new(:valid?, :return_type, :diagnostics)
11-
Diagnostic = Struct.new(:message, :code, :severity, :node_id, :parameter_index)
10+
class BunNotFound < Triangulum::Error
11+
end
12+
13+
Result = Struct.new(:valid?, :return_type, :diagnostics, keyword_init: true)
14+
Diagnostic = Struct.new(:message, :code, :severity, :node_id, :parameter_index, keyword_init: true)
1215

1316
ENTRYPOINT = File.expand_path('js/single-validation.js', __dir__)
1417
BUN_EXE = Dir.glob(File.expand_path('../../exe/*/bun', __dir__)).find do |path|
@@ -35,6 +38,8 @@ def validate
3538
private
3639

3740
def run_ts_triangulum(input)
41+
raise BunNotFound, "No bundled bun binary found for #{Gem::Platform.local}" if BUN_EXE.nil?
42+
3843
stdout_s, stderr_s, status = Open3.capture3(
3944
BUN_EXE, 'run', ENTRYPOINT,
4045
stdin_data: input
@@ -70,15 +75,15 @@ def parse_output(output)
7075
json = JSON.parse(output, symbolize_names: true)
7176

7277
Result.new(
73-
json[:isValid],
74-
json[:returnType],
75-
json[:diagnostics].map do |diagnostic|
78+
valid?: json[:isValid],
79+
return_type: json[:returnType],
80+
diagnostics: json[:diagnostics].map do |diagnostic|
7681
Diagnostic.new(
77-
diagnostic[:message],
78-
diagnostic[:code],
79-
diagnostic[:severity],
80-
diagnostic[:nodeId],
81-
diagnostic[:parameterIndex]
82+
message: diagnostic[:message],
83+
code: diagnostic[:code],
84+
severity: diagnostic[:severity],
85+
node_id: diagnostic[:nodeId],
86+
parameter_index: diagnostic[:parameterIndex]
8287
)
8388
end
8489
)

gem/rakelib/bun.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
BUN_VERSION = 'v1.3.11'
4+
5+
# rubocop:disable Layout/LineLength
6+
# rubygems platform name => [bun release zip filename, sha256 checksum]
7+
BUN_PLATFORMS = {
8+
'arm64-darwin' => %w[bun-darwin-aarch64.zip 6f5a3467ed9caec4795bf78cd476507d9f870c7d57b86c945fcb338126772ffc],
9+
'x86_64-darwin' => %w[bun-darwin-x64.zip c4fe2b9247218b0295f24e895aaec8fee62e74452679a9026b67eacbd611a286],
10+
'x86_64-linux-gnu' => %w[bun-linux-x64.zip 8611ba935af886f05a6f38740a15160326c15e5d5d07adef966130b4493607ed],
11+
'x86_64-linux-musl' => %w[bun-linux-x64-musl.zip b0fce3bc4fab52f26a1e0d8886dc07fd0c0eb2a274cb343b59c83a2d5997b5b1],
12+
'aarch64-linux-gnu' => %w[bun-linux-aarch64.zip d13944da12a53ecc74bf6a720bd1d04c4555c038dfe422365356a7be47691fdf],
13+
'aarch64-linux-musl' => %w[bun-linux-aarch64-musl.zip 0f5bf5dc3f276053196274bb84f90a44e2fa40c9432bd6757e3247a8d9476a3d]
14+
}.freeze
15+
# rubocop:enable Layout/LineLength
16+
17+
def bun_download_url(filename)
18+
"https://github.com/oven-sh/bun/releases/download/bun-#{BUN_VERSION}/#{filename}"
19+
end

gem/rakelib/entrypoints.rake

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
desc 'Bundle the TypeScript entrypoints into single JS files'
4+
task 'build:entrypoints' do
5+
rm_rf 'lib/triangulum/js'
6+
directory 'lib/triangulum/js'
7+
8+
entrypoints = %w[single-validation]
9+
10+
entrypoints.each do |entrypoint|
11+
entrypoint_src = File.expand_path("../../entrypoint/#{entrypoint}.ts", __dir__)
12+
entrypoint_dst = File.expand_path("../lib/triangulum/js/#{entrypoint}.js", __dir__)
13+
14+
sh 'bun', 'build', entrypoint_src, '--outfile', entrypoint_dst, '--target', 'bun'
15+
end
16+
end

gem/rakelib/package.rake

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# frozen_string_literal: true
2+
3+
require 'rubygems/package_task'
4+
require 'open-uri'
5+
require 'digest'
6+
require_relative 'bun'
7+
8+
desc 'Clean downloaded bun binaries'
9+
task 'clobber:bun' do
10+
BUN_PLATFORMS.each_key do |platform|
11+
bun_path = File.join('exe', platform, 'bun')
12+
rm bun_path if File.exist?(bun_path)
13+
end
14+
end
15+
16+
task clobber: %i[clobber:bun]
17+
18+
exepaths = []
19+
20+
TRIANGULUM_GEMSPEC = Bundler.load_gemspec('triangulum.gemspec')
21+
22+
BUN_PLATFORMS.each do |platform, (zip_filename, expected_checksum)|
23+
TRIANGULUM_GEMSPEC.dup.tap do |gemspec|
24+
exedir = File.join('exe', platform)
25+
exepath = File.join(exedir, 'bun')
26+
27+
exepaths << exepath
28+
29+
gemspec.platform = platform
30+
gemspec.files += [exepath]
31+
32+
gem_path = Gem::PackageTask.new(gemspec).define
33+
desc "Build the #{platform} gem"
34+
task "gem:#{platform}" => [gem_path]
35+
36+
directory exedir
37+
file exepath => [exedir] do
38+
url = bun_download_url(zip_filename)
39+
warn "Downloading #{exepath} from #{url} ..."
40+
41+
URI.open(url) do |remote| # rubocop:disable Security/Open
42+
zip_data = remote.read
43+
44+
actual_checksum = Digest::SHA256.hexdigest(zip_data)
45+
unless actual_checksum == expected_checksum
46+
raise "Checksum mismatch for #{zip_filename}: expected #{expected_checksum}, got #{actual_checksum}"
47+
end
48+
49+
require 'zip'
50+
Zip::File.open_buffer(zip_data) do |zip|
51+
bun_entry = zip.find { |e| File.basename(e.name) == 'bun' }
52+
raise "bun binary not found in #{zip_filename}" unless bun_entry
53+
54+
File.binwrite(exepath, bun_entry.get_input_stream.read)
55+
end
56+
end
57+
58+
FileUtils.chmod(0o755, exepath, verbose: true)
59+
end
60+
end
61+
end
62+
63+
desc 'Download all bun binaries'
64+
task download: exepaths

gem/rakelib/push.rake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# frozen_string_literal: true
2+
3+
desc 'Push all platform gems to RubyGems'
4+
task 'push:all' do
5+
Dir['pkg/*.gem'].each do |gem_file|
6+
sh 'gem', 'push', gem_file
7+
end
8+
end

gem/triangulum.gemspec

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ Gem::Specification.new do |spec|
1919

2020
# Specify which files should be added to the gem when it is released.
2121
spec.files = Dir.glob('lib/**/*', base: __dir__).select { |f| File.file?(File.join(__dir__, f)) } + ['README.md']
22-
spec.bindir = 'exe'
23-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
2422
spec.require_paths = ['lib']
2523

2624
spec.add_dependency 'base64', '~> 0.3'

0 commit comments

Comments
 (0)