Skip to content

Commit 34afaa0

Browse files
committed
feat: Scripts for publishing gems
1 parent 13470bd commit 34afaa0

File tree

6 files changed

+122
-61
lines changed

6 files changed

+122
-61
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
test/tmp/
66
.direnv/
77
pkg/
8+
9+
# Offline dependency sources
10+
.codex/deps_src/
11+
.codex/internet_resources/

MAINTANERS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ Two Ruby gems are published from this repository:
5252
* **codetracer_pure_ruby_recorder** – a pure Ruby fallback without the
5353
native extension.
5454

55+
A helper script is available to build and push all gems in one go:
56+
57+
```bash
58+
ruby scripts/publish_gems.rb
59+
```
60+
5561
### Native extension gem
5662

5763
1. Install the development dependencies:
@@ -89,3 +95,6 @@ gem push codetracer_pure_ruby_recorder-<version>.gem
8995

9096
Ensure the version matches the native extension gem so that both
9197
packages can be used interchangeably.
98+
99+
All the above steps are automated by `scripts/publish_gems.rb` which
100+
builds and publishes the pure Ruby gem and all native variants.

bin/codetracer-pure-ruby-recorder

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env ruby
2+
require 'rbconfig'
3+
script = File.expand_path('../src/trace.rb', __dir__)
4+
exec RbConfig.ruby, script, *ARGV
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Gem::Specification.new do |spec|
2+
spec.name = 'codetracer_pure_ruby_recorder'
3+
spec.version = '0.1.0'
4+
spec.authors = ['Metacraft Labs']
5+
spec.email = ['[email protected]']
6+
7+
spec.summary = 'CodeTracer Ruby recorder implemented purely in Ruby'
8+
spec.description = 'Ruby tracer that records execution steps using only Ruby code.'
9+
spec.license = 'MIT'
10+
spec.homepage = 'https://github.com/metacraft-labs/codetracer-ruby-recorder'
11+
12+
spec.files = Dir['src/**/*', 'bin/*', 'README.md', 'LICENSE']
13+
spec.require_paths = ['src']
14+
spec.bindir = 'bin'
15+
spec.executables = ['codetracer-pure-ruby-recorder']
16+
end

scripts/publish_gems.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require 'fileutils'
5+
6+
TARGETS = [
7+
'x86_64-unknown-linux-gnu',
8+
'aarch64-unknown-linux-gnu',
9+
'x86_64-apple-darwin',
10+
'aarch64-apple-darwin',
11+
'x86_64-pc-windows-msvc'
12+
].freeze
13+
14+
15+
def run(cmd, env = {})
16+
command = env.map { |k, v| "#{k}=#{v}" }.join(' ')
17+
command = [command, cmd].reject(&:empty?).join(' ')
18+
puts "$ #{command}"
19+
system(env, *cmd.split(' ')) || abort("Command failed: #{command}")
20+
end
21+
22+
# Build and publish native extension gems
23+
TARGETS.each do |target|
24+
run('rake cross_native_gem', 'RB_SYS_CARGO_TARGET' => target)
25+
gem_file = Dir['pkg/codetracer-ruby-recorder-*.gem'].max_by { |f| File.mtime(f) }
26+
run("gem push #{gem_file}")
27+
FileUtils.rm_f(gem_file)
28+
end
29+
30+
# Build and publish pure Ruby gem
31+
run('gem build codetracer_pure_ruby_recorder.gemspec')
32+
pure_gem = Dir['codetracer_pure_ruby_recorder-*.gem'].max_by { |f| File.mtime(f) }
33+
run("gem push #{pure_gem}")
34+
FileUtils.rm_f(pure_gem)

src/trace.rb

Lines changed: 55 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@
55
require 'json'
66
require_relative 'recorder'
77

8-
if ARGV[0].nil?
9-
$stderr.puts("ruby trace.rb <program> [<args>]")
10-
exit(1)
11-
end
12-
13-
program = ARGV[0]
14-
158
# Warning:
169
# probably related to our development env:
1710
# if we hit an `incompatible library version` error, like
@@ -82,6 +75,7 @@ def initialize(record)
8275
@trace_stopped = false
8376
@record = record
8477
@ignore_list = []
78+
setup_tracepoints
8579
end
8680

8781
def stop_tracing
@@ -97,6 +91,32 @@ def ignore(path)
9791
@ignore_list << path
9892
end
9993

94+
def setup_tracepoints
95+
@calls_tracepoint = TracePoint.new(:call) do |tp|
96+
deactivate
97+
record_call(tp)
98+
activate
99+
end
100+
101+
@return_tracepoint = TracePoint.new(:return) do |tp|
102+
deactivate
103+
record_return(tp)
104+
activate
105+
end
106+
107+
@line_tracepoint = TracePoint.new(:line) do |tp|
108+
deactivate
109+
record_step(tp)
110+
activate
111+
end
112+
113+
@raise_tracepoint = TracePoint.new(:raise) do |tp|
114+
deactivate
115+
record_exception(tp)
116+
activate
117+
end
118+
end
119+
100120
def prepare_args(tp)
101121
args_after_self = tp.parameters.map do |(kind, name)|
102122
value = if tp.binding.nil? || name.nil?
@@ -229,64 +249,38 @@ def load_variables(binding)
229249

230250
$tracer = Tracer.new($codetracer_record)
231251

232-
# also possible :c_call, :b_call: for now record ruby calls (:call)
233-
# c_call: c lang
234-
# b_call: block entry
235-
# https://rubyapi.org/3.4/o/tracepoint
236-
$tracer.calls_tracepoint = TracePoint.new(:call) do |tp|
237-
$tracer.deactivate
238-
$tracer.record_call(tp)
239-
$tracer.activate
240-
end
252+
if __FILE__ == $PROGRAM_NAME
253+
if ARGV[0].nil?
254+
$stderr.puts('ruby trace.rb <program> [<args>]')
255+
exit(1)
256+
end
241257

242-
$tracer.return_tracepoint = TracePoint.new(:return) do |tp|
243-
$tracer.deactivate
244-
$tracer.record_return(tp)
245-
$tracer.activate
246-
end
258+
program = ARGV[0]
247259

248-
$tracer.line_tracepoint = TracePoint.new(:line) do |tp|
249-
$tracer.deactivate
250-
$tracer.record_step(tp)
251-
$tracer.activate
252-
end
260+
$tracer.record.register_call('', 1, '<top-level>', [])
261+
$tracer.ignore('lib/ruby')
262+
$tracer.ignore('trace.rb')
263+
$tracer.ignore('recorder.rb')
264+
$tracer.ignore('<internal:')
265+
$tracer.ignore('gems/')
253266

254-
$tracer.raise_tracepoint = TracePoint.new(:raise) do |tp|
255-
$tracer.deactivate
256-
$tracer.record_exception(tp)
267+
trace_args = ARGV
268+
ARGV = ARGV[1..-1]
257269
$tracer.activate
258-
end
270+
begin
271+
Kernel.load(program)
272+
rescue Exception => e
273+
old_puts ''
274+
old_puts '==== trace.rb error while tracing program ==='
275+
old_puts 'ERROR'
276+
old_puts e
277+
old_puts e.backtrace
278+
old_puts '====================='
279+
old_puts ''
280+
end
281+
ARGV = trace_args
259282

260-
$tracer.record.register_call("", 1, "<top-level>", [])
261-
$tracer.ignore('lib/ruby')
262-
$tracer.ignore('trace.rb')
263-
$tracer.ignore('recorder.rb')
264-
$tracer.ignore('<internal:')
265-
$tracer.ignore('gems/')
266-
283+
$tracer.stop_tracing
267284

268-
trace_args = ARGV
269-
ARGV = ARGV[1..-1]
270-
$tracer.activate
271-
begin
272-
Kernel.load(program)
273-
rescue Exception => e
274-
# important: rescue Exception,
275-
# not just rescue as we originally did
276-
# because a simple `rescue` doesn't catch some errors
277-
# like SystemExit and others
278-
# (when we call `exit` in the trace program and others)
279-
# https://stackoverflow.com/questions/5118745/is-systemexit-a-special-kind-of-exception
280-
old_puts ""
281-
old_puts "==== trace.rb error while tracing program ==="
282-
old_puts "ERROR"
283-
old_puts e
284-
old_puts e.backtrace
285-
old_puts "====================="
286-
old_puts ""
285+
$tracer.record.serialize(program)
287286
end
288-
ARGV = trace_args
289-
290-
$tracer.stop_tracing
291-
292-
$tracer.record.serialize(program)

0 commit comments

Comments
 (0)