pyroscope 0.1.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ extern crate cbindgen;
2
+
3
+ use cbindgen::Config;
4
+
5
+ fn main() {
6
+ let bindings = {
7
+ let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
8
+ let config = Config::from_file("cbindgen.toml").unwrap();
9
+ cbindgen::generate_with_config(&crate_dir, config).unwrap()
10
+ };
11
+ bindings.write_to_file("include/rbspy.h");
12
+ }
@@ -0,0 +1,22 @@
1
+ # The language to output bindings in
2
+ language = "C"
3
+ documentation_style = "C"
4
+
5
+ style = "type"
6
+
7
+ # An optional name to use as an include guard
8
+ include_guard = "RBSPY_H_"
9
+ # include a comment with the version of cbindgen used to generate the file
10
+ include_version = true
11
+
12
+ # An optional string of text to output at the beginning of the generated file
13
+ header = "/* Licensed under Apache-2.0 */"
14
+ autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
15
+
16
+ braces = "SameLine"
17
+ tab_width = 2
18
+ line_length = 80
19
+
20
+ [parse]
21
+ # Do not parse dependent crates
22
+ parse_deps = false
@@ -0,0 +1,11 @@
1
+ require 'mkmf'
2
+ require 'rake'
3
+
4
+ create_makefile('rbspy')
5
+
6
+ app = Rake.application
7
+ app.init
8
+ app.add_import 'Rakefile'
9
+ app.load_rakefile
10
+
11
+ app['default'].invoke
@@ -0,0 +1,183 @@
1
+ use ffikit::Signal;
2
+ use pyroscope::backend::Tag;
3
+ use pyroscope::PyroscopeAgent;
4
+ use pyroscope_rbspy::{rbspy_backend, RbspyConfig};
5
+ use std::collections::hash_map::DefaultHasher;
6
+ use std::ffi::CStr;
7
+ use std::hash::Hasher;
8
+ use std::os::raw::c_char;
9
+
10
+ #[no_mangle]
11
+ pub extern "C" fn initialize_agent(
12
+ application_name: *const c_char, server_address: *const c_char, auth_token: *const c_char,
13
+ sample_rate: u32, detect_subprocesses: bool, on_cpu: bool, report_pid: bool,
14
+ report_thread_id: bool, tags: *const c_char,
15
+ ) -> bool {
16
+ // Initialize FFIKit
17
+ let recv = ffikit::initialize_ffi().unwrap();
18
+
19
+ let application_name = unsafe { CStr::from_ptr(application_name) }
20
+ .to_str()
21
+ .unwrap()
22
+ .to_string();
23
+
24
+ let server_address = unsafe { CStr::from_ptr(server_address) }
25
+ .to_str()
26
+ .unwrap()
27
+ .to_string();
28
+
29
+ let auth_token = unsafe { CStr::from_ptr(auth_token) }
30
+ .to_str()
31
+ .unwrap()
32
+ .to_string();
33
+
34
+ let tags_string = unsafe { CStr::from_ptr(tags) }
35
+ .to_str()
36
+ .unwrap()
37
+ .to_string();
38
+
39
+ let pid = std::process::id();
40
+
41
+ let rbspy_config = RbspyConfig::new(pid.try_into().unwrap())
42
+ .sample_rate(sample_rate)
43
+ .lock_process(false)
44
+ .with_subprocesses(detect_subprocesses)
45
+ .on_cpu(on_cpu)
46
+ .report_pid(report_pid)
47
+ .report_thread_id(report_thread_id);
48
+
49
+ let tags_ref = tags_string.as_str();
50
+ let tags = string_to_tags(tags_ref);
51
+ let rbspy = rbspy_backend(rbspy_config);
52
+
53
+ let mut agent_builder = PyroscopeAgent::builder(server_address, application_name)
54
+ .backend(rbspy)
55
+ .tags(tags);
56
+
57
+ if auth_token != "" {
58
+ agent_builder = agent_builder.auth_token(auth_token);
59
+ }
60
+
61
+ let agent = agent_builder.build().unwrap();
62
+
63
+ let agent_running = agent.start().unwrap();
64
+
65
+ std::thread::spawn(move || {
66
+ while let Ok(signal) = recv.recv() {
67
+ match signal {
68
+ Signal::Kill => {
69
+ agent_running.stop().unwrap();
70
+ break;
71
+ }
72
+ Signal::AddGlobalTag(name, value) => {
73
+ agent_running.add_global_tag(Tag::new(name, value)).unwrap();
74
+ }
75
+ Signal::RemoveGlobalTag(name, value) => {
76
+ agent_running
77
+ .remove_global_tag(Tag::new(name, value))
78
+ .unwrap();
79
+ }
80
+ Signal::AddThreadTag(thread_id, key, value) => {
81
+ let tag = Tag::new(key, value);
82
+ agent_running.add_thread_tag(thread_id, tag).unwrap();
83
+ }
84
+ Signal::RemoveThreadTag(thread_id, key, value) => {
85
+ let tag = Tag::new(key, value);
86
+ agent_running.remove_thread_tag(thread_id, tag).unwrap();
87
+ }
88
+ }
89
+ }
90
+ });
91
+
92
+ true
93
+ }
94
+
95
+ #[no_mangle]
96
+ pub extern "C" fn drop_agent() -> bool {
97
+ // Send Kill signal to the FFI merge channel.
98
+ ffikit::send(ffikit::Signal::Kill).unwrap();
99
+
100
+ true
101
+ }
102
+
103
+ #[no_mangle]
104
+ pub extern "C" fn add_thread_tag(thread_id: u64, key: *const c_char, value: *const c_char) -> bool {
105
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
106
+ let value = unsafe { CStr::from_ptr(value) }
107
+ .to_str()
108
+ .unwrap()
109
+ .to_owned();
110
+
111
+ let pid = std::process::id();
112
+ let mut hasher = DefaultHasher::new();
113
+ hasher.write_u64(thread_id % pid as u64);
114
+ let id = hasher.finish();
115
+
116
+ ffikit::send(ffikit::Signal::AddThreadTag(id, key, value)).unwrap();
117
+
118
+ true
119
+ }
120
+
121
+ #[no_mangle]
122
+ pub extern "C" fn remove_thread_tag(
123
+ thread_id: u64, key: *const c_char, value: *const c_char,
124
+ ) -> bool {
125
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
126
+ let value = unsafe { CStr::from_ptr(value) }
127
+ .to_str()
128
+ .unwrap()
129
+ .to_owned();
130
+
131
+ let pid = std::process::id();
132
+ let mut hasher = DefaultHasher::new();
133
+ hasher.write_u64(thread_id % pid as u64);
134
+ let id = hasher.finish();
135
+
136
+ ffikit::send(ffikit::Signal::RemoveThreadTag(id, key, value)).unwrap();
137
+
138
+ true
139
+ }
140
+
141
+ #[no_mangle]
142
+ pub extern "C" fn add_global_tag(key: *const c_char, value: *const c_char) -> bool {
143
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
144
+ let value = unsafe { CStr::from_ptr(value) }
145
+ .to_str()
146
+ .unwrap()
147
+ .to_owned();
148
+
149
+ ffikit::send(ffikit::Signal::AddGlobalTag(key, value)).unwrap();
150
+
151
+ true
152
+ }
153
+
154
+ #[no_mangle]
155
+ pub extern "C" fn remove_global_tag(key: *const c_char, value: *const c_char) -> bool {
156
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
157
+ let value = unsafe { CStr::from_ptr(value) }
158
+ .to_str()
159
+ .unwrap()
160
+ .to_owned();
161
+
162
+ ffikit::send(ffikit::Signal::RemoveGlobalTag(key, value)).unwrap();
163
+
164
+ true
165
+ }
166
+
167
+ // Convert a string of tags to a Vec<(&str, &str)>
168
+ fn string_to_tags<'a>(tags: &'a str) -> Vec<(&'a str, &'a str)> {
169
+ let mut tags_vec = Vec::new();
170
+ // check if string is empty
171
+ if tags.is_empty() {
172
+ return tags_vec;
173
+ }
174
+
175
+ for tag in tags.split(',') {
176
+ let mut tag_split = tag.split('=');
177
+ let key = tag_split.next().unwrap();
178
+ let value = tag_split.next().unwrap();
179
+ tags_vec.push((key, value));
180
+ }
181
+
182
+ tags_vec
183
+ }
@@ -0,0 +1,20 @@
1
+ [package]
2
+ name = "thread_id"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [lib]
7
+ name = "thread_id"
8
+ crate-type = ["cdylib"]
9
+
10
+ [dependencies]
11
+ libc = "*"
12
+
13
+ [build-dependencies]
14
+ cbindgen = "0.20.0"
15
+
16
+ [profile.release]
17
+ opt-level= "z"
18
+ debug = false
19
+ lto = true
20
+ codegen-units = 1
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+
5
+ class ThreadIdRakeCargoHelper
6
+ attr_reader :gemname
7
+
8
+ def initialize(gemname=File.basename(__dir__))
9
+ @gemname = gemname
10
+ end
11
+
12
+ def self.command?(name)
13
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
14
+ ENV["PATH"].split(File::PATH_SEPARATOR).any? do |path|
15
+ exts.any? do |ext|
16
+ exe = File.join(path, "#{name}#{ext}")
17
+ File.executable?(exe) && !File.directory?(exe)
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.rust_toolchain
23
+ # return env variable if set
24
+ target = ENV["RUST_TARGET"]
25
+ return target if target
26
+
27
+ str = `rustc --version --verbose`
28
+ info = str.lines.map {|l| l.chomp.split(/:\s+/, 2)}.drop(1).to_h
29
+ info["host"]
30
+ end
31
+
32
+ def self.cargo_target_dir
33
+ return @cargo_target_dir if defined? @cargo_target_dir
34
+
35
+ str = `cargo metadata --format-version 1 --offline --no-deps --quiet`
36
+ begin
37
+ require "json"
38
+ dir = JSON.parse(str)["target_directory"]
39
+ rescue LoadError # json is usually part of the stdlib, but just in case
40
+ /"target_directory"\s*:\s*"(?<dir>[^"]*)"/ =~ str
41
+ end
42
+ @cargo_target_dir = dir || "target"
43
+ end
44
+
45
+ def self.flags
46
+ cc_flags = Shellwords.split(RbConfig.expand(RbConfig::MAKEFILE_CONFIG["CC"].dup))
47
+
48
+ ["-C", "linker=#{cc_flags.shift}",
49
+ *cc_flags.flat_map {|a| ["-C", "link-arg=#{a}"] },
50
+ "-L", "native=#{RbConfig::CONFIG["libdir"]}",
51
+ *dld_flags,
52
+ *platform_flags]
53
+ end
54
+
55
+ def self.dld_flags
56
+ Shellwords.split(RbConfig::CONFIG["DLDFLAGS"]).flat_map do |arg|
57
+ arg = arg.gsub(/\$\((\w+)\)/) do
58
+ $1 == "DEFFILE" ? nil : RbConfig::CONFIG[name]
59
+ end.strip
60
+ next [] if arg.empty?
61
+
62
+ transform_flag(arg)
63
+ end
64
+ end
65
+
66
+ def self.platform_flags
67
+ return unless RbConfig::CONFIG["target_os"] =~ /mingw/i
68
+
69
+ [*Shellwords.split(RbConfig::CONFIG["LIBRUBYARG"]).flat_map {|arg| transform_flag(arg)},
70
+ "-C", "link-arg=-Wl,--dynamicbase",
71
+ "-C", "link-arg=-Wl,--disable-auto-image-base",
72
+ "-C", "link-arg=-static-libgcc"]
73
+ end
74
+
75
+ def self.transform_flag(arg)
76
+ k, v = arg.split(/(?<=..)/, 2)
77
+ case k
78
+ when "-L"
79
+ [k, "native=#{v}"]
80
+ when "-l"
81
+ [k, v]
82
+ when "-F"
83
+ ["-l", "framework=#{v}"]
84
+ else
85
+ ["-C", "link_arg=#{k}#{v}"]
86
+ end
87
+ end
88
+
89
+ def install_dir
90
+ File.expand_path(File.join("..", "..", "lib", gemname), __dir__)
91
+ end
92
+
93
+ def rust_name
94
+ prefix = "lib" unless Gem.win_platform?
95
+ suffix = if RbConfig::CONFIG["target_os"] =~ /darwin/i
96
+ ".dylib"
97
+ elsif Gem.win_platform?
98
+ ".dll"
99
+ else
100
+ ".so"
101
+ end
102
+ "#{prefix}#{gemname}#{suffix}"
103
+ end
104
+
105
+ def ruby_name
106
+ "#{gemname}.#{RbConfig::CONFIG["DLEXT"]}"
107
+ end
108
+
109
+ end
110
+
111
+ task default: [:thread_id_install, :thread_id_clean]
112
+ task thread_id: [:thread_id_install, :thread_id_clean]
113
+
114
+ desc "set dev mode for subsequent task, run like `rake dev install`"
115
+ task :thread_id_dev do
116
+ @dev = true
117
+ end
118
+
119
+ desc "build gem native extension and copy to lib"
120
+ task thread_id_install: [:thread_id_cd, :thread_id_build] do
121
+ helper = ThreadIdRakeCargoHelper.new
122
+ profile_dir = @dev ? "debug" : "release"
123
+ arch_dir = RbspyRakeCargoHelper.rust_toolchain
124
+ source = File.join(ThreadIdRakeCargoHelper.cargo_target_dir, arch_dir, profile_dir, helper.rust_name)
125
+ dest = File.join(helper.install_dir, helper.ruby_name)
126
+ mkdir_p(helper.install_dir)
127
+ rm(dest) if File.exist?(dest)
128
+ cp(source, dest)
129
+ end
130
+
131
+ desc "build gem native extension"
132
+ task thread_id_build: [:thread_id_cargo, :thread_id_cd] do
133
+ sh "cargo", "rustc", *(["--locked", "--release"] unless @dev), "--target=#{RbspyRakeCargoHelper.rust_toolchain}", "--", *RbspyRakeCargoHelper.flags
134
+ end
135
+
136
+ desc "clean up release build artifacts"
137
+ task thread_id_clean: [:thread_id_cargo, :thread_id_cd] do
138
+ sh "cargo clean --release"
139
+ end
140
+
141
+ desc "clean up build artifacts"
142
+ task thread_id_clobber: [:thread_id_cargo, :thread_id_cd] do
143
+ sh "cargo clean"
144
+ end
145
+
146
+ desc "check for cargo"
147
+ task :thread_id_cargo do
148
+ raise <<-MSG unless ThreadIdRakeCargoHelper.command?("cargo")
149
+ This gem requires a Rust compiler and the `cargo' build tool to build the
150
+ gem's native extension. See https://www.rust-lang.org/tools/install for
151
+ how to install Rust. `cargo' is usually part of the Rust installation.
152
+ MSG
153
+
154
+ raise <<-MSG if Gem.win_platform? && ThreadIdRakeCargoHelper.rust_toolchain !~ /gnu/
155
+ Found Rust toolchain `#{ThreadIdRakeCargoHelper.rust_toolchain}' but the gem native
156
+ extension requires the gnu toolchain on Windows.
157
+ MSG
158
+ end
159
+
160
+ # ensure task is running in the right dir
161
+ task :thread_id_cd do
162
+ cd(__dir__) unless __dir__ == pwd
163
+ end
@@ -0,0 +1,12 @@
1
+ extern crate cbindgen;
2
+
3
+ use cbindgen::Config;
4
+
5
+ fn main() {
6
+ let bindings = {
7
+ let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
8
+ let config = Config::from_file("cbindgen.toml").unwrap();
9
+ cbindgen::generate_with_config(&crate_dir, config).unwrap()
10
+ };
11
+ bindings.write_to_file("include/thread_id.h");
12
+ }
@@ -0,0 +1,22 @@
1
+ # The language to output bindings in
2
+ language = "C"
3
+ documentation_style = "C"
4
+
5
+ style = "type"
6
+
7
+ # An optional name to use as an include guard
8
+ include_guard = "RBSPY_H_"
9
+ # include a comment with the version of cbindgen used to generate the file
10
+ include_version = true
11
+
12
+ # An optional string of text to output at the beginning of the generated file
13
+ header = "/* Licensed under Apache-2.0 */"
14
+ autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
15
+
16
+ braces = "SameLine"
17
+ tab_width = 2
18
+ line_length = 80
19
+
20
+ [parse]
21
+ # Do not parse dependent crates
22
+ parse_deps = false
@@ -0,0 +1,11 @@
1
+ require 'mkmf'
2
+ require 'rake'
3
+
4
+ create_makefile('thread_id')
5
+
6
+ app = Rake.application
7
+ app.init
8
+ app.add_import 'Rakefile'
9
+ app.load_rakefile
10
+
11
+ app['default'].invoke
@@ -0,0 +1,4 @@
1
+ #[no_mangle]
2
+ pub extern "C" fn thread_id() -> u64 {
3
+ unsafe { libc::pthread_self() as u64 }
4
+ }
@@ -1,3 +1,3 @@
1
1
  module Pyroscope
2
- VERSION = "0.1.1".freeze
2
+ VERSION = '0.3.1'.freeze
3
3
  end
data/lib/pyroscope.rb CHANGED
@@ -1,60 +1,103 @@
1
- require "pyroscope/version"
2
- require "pyroscope_c"
1
+ require 'ffi'
3
2
 
4
3
  module Pyroscope
5
- Config = Struct.new(:app_name, :server_address, :auth_token, :sample_rate, :with_subprocesses, :log_level, :tags)
4
+ module Rust
5
+ extend FFI::Library
6
+ ffi_lib File.expand_path(File.dirname(__FILE__)) + "/rbspy/rbspy.#{RbConfig::CONFIG["DLEXT"]}"
7
+ attach_function :initialize_agent, [:string, :string, :string, :int, :bool, :bool, :bool, :bool, :string], :bool
8
+ attach_function :add_thread_tag, [:uint64, :string, :string], :bool
9
+ attach_function :remove_thread_tag, [:uint64, :string, :string], :bool
10
+ attach_function :add_global_tag, [:string, :string], :bool
11
+ attach_function :remove_global_tag, [:string, :string], :bool
12
+ attach_function :drop_agent, [], :bool
13
+ end
14
+
15
+ module Utils
16
+ extend FFI::Library
17
+ ffi_lib File.expand_path(File.dirname(__FILE__)) + "/thread_id/thread_id.#{RbConfig::CONFIG["DLEXT"]}"
18
+ attach_function :thread_id, [], :uint64
19
+ end
20
+
21
+ Config = Struct.new(:application_name, :app_name, :server_address, :auth_token, :sample_rate, :detect_subprocesses, :on_cpu, :report_pid, :report_thread_id, :log_level, :tags) do
22
+ def initialize(*)
23
+ self.application_name = ''
24
+ self.server_address = 'http://localhost:4040'
25
+ self.auth_token = ''
26
+ self.sample_rate = 100
27
+ self.detect_subprocesses = false
28
+ self.on_cpu = true
29
+ self.report_pid = false
30
+ self.report_thread_id = false
31
+ self.log_level = 'info'
32
+ self.tags = {}
33
+ super
34
+ end
35
+ end
6
36
 
7
37
  class << self
8
38
  def configure
9
- @configuration = Config.new
10
- yield @configuration
11
- _start(
12
- @configuration.app_name,
13
- @configuration.server_address,
14
- @configuration.auth_token || "",
15
- @configuration.sample_rate || 100,
16
- @configuration.with_subprocesses || 0,
17
- @configuration.log_level || "error",
18
- )
19
- tag(@configuration.tags) if @configuration.tags
20
- end
39
+ @config = Config.new
21
40
 
22
- def stop
23
- _stop
24
- end
41
+ # Pass config to the block
42
+ yield @config
25
43
 
26
- def change_name(new_name)
27
- _change_name(new_name)
44
+ Rust.initialize_agent(
45
+ @config.app_name || @config.application_name || "",
46
+ @config.server_address || "",
47
+ @config.auth_token || "",
48
+ @config.sample_rate || 100,
49
+ @config.detect_subprocesses || false,
50
+ @config.on_cpu || false,
51
+ @config.report_pid || false,
52
+ @config.report_thread_id || false,
53
+ tags_to_string(@config.tags || {})
54
+ )
28
55
  end
29
56
 
30
57
  def tag_wrapper(tags)
31
- tag(tags)
32
-
58
+ tid = thread_id
59
+ _add_tags(tid, tags)
33
60
  begin
34
61
  yield
35
62
  ensure
36
- remove_tags(*tags.keys)
63
+ _remove_tags(tid, tags)
37
64
  end
38
65
  end
39
66
 
40
67
  def tag(tags)
41
- tags.each_pair do |key, val|
42
- _set_tag(key.to_s, val.to_s)
43
- end
68
+ warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
44
69
  end
45
70
 
46
- def remove_tags(*keys)
47
- keys.each do |key|
48
- _set_tag(key.to_s, "")
71
+ def remove_tags(*tags)
72
+ warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
73
+ end
74
+
75
+ # convert tags object to string
76
+ def tags_to_string(tags)
77
+ tags.map { |k, v| "#{k}=#{v}" }.join(',')
78
+ end
79
+
80
+ # get thread id
81
+ def thread_id
82
+ return Utils.thread_id
83
+ end
84
+
85
+ # add tags
86
+ def _add_tags(thread_id, tags)
87
+ tags.each do |tag_name, tag_value|
88
+ Rust.add_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
49
89
  end
50
90
  end
51
91
 
52
- def test_logger
53
- _test_logger
92
+ # remove tags
93
+ def _remove_tags(thread_id, tags)
94
+ tags.each do |tag_name, tag_value|
95
+ Rust.remove_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
96
+ end
54
97
  end
55
98
 
56
- def build_summary
57
- _build_summary
99
+ def drop
100
+ Rust.drop_agent
58
101
  end
59
102
  end
60
103
  end
data/pyroscope.gemspec CHANGED
@@ -1,27 +1,32 @@
1
- lib = File.expand_path('../lib', __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
-
4
- require 'pyroscope/version'
1
+ require_relative "lib/pyroscope/version"
5
2
 
6
3
  Gem::Specification.new do |s|
7
- s.name = "pyroscope"
8
- s.version = Pyroscope::VERSION
9
- s.summary = "pyroscope"
10
- s.description = "pyroscope client integration for ruby"
11
- s.authors = ["Pyroscope Team"]
12
- s.email = "contact@pyroscope.io"
13
- s.files = `git ls-files`.split("\n")
14
- s.files += Dir.glob("ext/**/**")
15
- # s.files << "lib/pyroscope_c.bundle"
16
- s.homepage = "http://rubygems.org/gems/pyroscope"
17
- s.license = "Apache-2.0"
18
- s.require_paths = ["lib"]
19
- s.require_paths << "ext/pyroscope"
20
- s.extensions << "ext/pyroscope/extconf.rb"
4
+ s.name = 'pyroscope'
5
+ s.version = Pyroscope::VERSION
6
+ s.summary = 'Pyroscope'
7
+ s.description = 'Pyroscope FFI Integration for Ruby'
8
+ s.authors = ['Pyroscope Team']
9
+ s.email = ['contact@pyroscope.io']
10
+ s.homepage = 'https://pyroscope.io'
11
+ s.license = 'Apache-2.0'
12
+
13
+ # Specify which files should be added to the gem when it is released.
14
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
15
+ #s.files = Dir.chdir(__dir__) do
16
+ #`git ls-files -z`.split("\x0").reject do |f|
17
+ #(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
18
+ #end
19
+ #end
20
+ s.files = `git ls-files -z`.split("\0").reject { |f| f =~ /^(\.|G|spec|Rakefile)/ }
21
+
22
+ s.platform = Gem::Platform::RUBY
23
+
24
+ s.required_ruby_version = ">= 2.5.9"
25
+
26
+ s.extensions = ['ext/rbspy/extconf.rb', 'ext/thread_id/extconf.rb']
27
+
28
+ s.add_dependency 'ffi'
21
29
 
22
- s.add_development_dependency "bundler"
23
- s.add_development_dependency "rake"
24
- s.add_development_dependency "rake-compiler"
25
- s.add_development_dependency "rubygems-tasks"
26
- s.add_development_dependency "rspec"
30
+ s.add_development_dependency 'bundler'
31
+ s.add_development_dependency 'rake', '~> 13.0'
27
32
  end
data/scripts/docker.sh ADDED
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ BUILD_DIR="/work"
5
+
6
+ docker run \
7
+ -w /work/pyroscope_ffi/ruby/elflib/rbspy \
8
+ -v `pwd`:/work \
9
+ quay.io/pypa/${BUILD_ARCH} \
10
+ sh manylinux.sh
11
+
12
+ docker run \
13
+ -w /work/pyroscope_ffi/ruby/elflib/thread_id \
14
+ -v `pwd`:/work \
15
+ quay.io/pypa/${BUILD_ARCH} \
16
+ sh manylinux.sh