rb_sys 0.9.63 → 0.9.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.yardopts +3 -0
- data/README.md +98 -0
- data/exe/rb-sys-dock +222 -125
- data/lib/rb_sys/cargo/metadata.rb +82 -20
- data/lib/rb_sys/error.rb +13 -7
- data/lib/rb_sys/extensiontask.rb +35 -3
- data/lib/rb_sys/mkmf.rb +21 -1
- data/lib/rb_sys/util/logger.rb +73 -0
- data/lib/rb_sys/version.rb +1 -1
- data.tar.gz.sig +1 -1
- metadata +7 -5
- metadata.gz.sig +0 -0
- data/sig/rb_sys.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5dc9ecb59d4b2cc130afff772c740063ee2bdbf5bdf15fb866aa6dcbb501d396
|
|
4
|
+
data.tar.gz: b9c2c65ef48e0c5400ea857bb75ad9ec85ffac300a4290bc6f20ef00ca5e8163
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c4acd2a28480da0b8adb18a48a806354afae12d963b9394f6ce9bd41f89c703a27dbe9a6bc52136f897ad7e64ccba70c9bbfd4231a9b209964d130dc703d8ad
|
|
7
|
+
data.tar.gz: 849c5b3fd8209dfe41b6a5efc0dbd06d6760e849b32cd0182915f9e1d5e011885ba64d56ef7c8f8ed286094ba4efaaec2ad5ffa1134690579223ae826e81ba54
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/.yardopts
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# The `rb_sys` gem
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://www.rubydoc.info/gems/rb_sys/frames)
|
|
5
|
+
[](https://join.slack.com/t/oxidize-rb/shared_invite/zt-16zv5tqte-Vi7WfzxCesdo2TqF_RYBCw)
|
|
6
|
+
|
|
7
|
+
The `rb_sys` gem is a Ruby gem makes it easy to build native Ruby extensions in Rust. It interops with the existing Ruby
|
|
8
|
+
native extension toolchains (i.e. `rake-compiler`) to make testing, building, and cross compilation of gems easy.
|
|
9
|
+
|
|
10
|
+
## `RbSys::ExtensionTask`
|
|
11
|
+
|
|
12
|
+
This gem provides a `RbSys::ExtensionTask` class that can be used to build a Ruby extension in Rust. It's a thin wrapper
|
|
13
|
+
around `Rake::ExtensionTask` that provides sane defaults for building Rust extensions.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# Rakefile
|
|
17
|
+
|
|
18
|
+
require "rb_sys/extensiontask"
|
|
19
|
+
|
|
20
|
+
GEMSPEC = Gem::Specification.load("my_gem.gemspec")
|
|
21
|
+
|
|
22
|
+
RbSys::ExtensionTask.new("my-crate-name", GEMSPEC) do |ext|
|
|
23
|
+
ext.lib_dir = "lib/my_gem"
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## `create_rust_makefile`
|
|
28
|
+
|
|
29
|
+
This gem provides a simple helper to build a Ruby compatible Makefile for you Rust extension. For a full example, see
|
|
30
|
+
the [examples](./../examples) directory.
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# ext/rust_reverse/extconf.rb
|
|
34
|
+
|
|
35
|
+
# We need to require mkmf *first* this since `rake-compiler` injects code here for cross compilation
|
|
36
|
+
require "mkmf"
|
|
37
|
+
require "rb_sys/mkmf"
|
|
38
|
+
|
|
39
|
+
create_rust_makefile("rust_reverse") do |r|
|
|
40
|
+
# Create debug builds in dev. Make sure that release gems are compiled with
|
|
41
|
+
# `RB_SYS_CARGO_PROFILE=release` (optional)
|
|
42
|
+
r.profile = ENV.fetch("RB_SYS_CARGO_PROFILE", :dev).to_sym
|
|
43
|
+
|
|
44
|
+
# Can be overridden with `RB_SYS_CARGO_FEATURES` env var (optional)
|
|
45
|
+
r.features = ["test-feature"]
|
|
46
|
+
|
|
47
|
+
# You can add whatever env vars you want to the env hash (optional)
|
|
48
|
+
r.env = {"FOO" => "BAR"}
|
|
49
|
+
|
|
50
|
+
# If your Cargo.toml is in a different directory, you can specify it here (optional)
|
|
51
|
+
r.ext_dir = "."
|
|
52
|
+
|
|
53
|
+
# Extra flags to pass to the $RUSTFLAGS environment variable (optional)
|
|
54
|
+
r.extra_rustflags = ["--cfg=some_nested_config_var_for_crate"]
|
|
55
|
+
|
|
56
|
+
# Force a rust toolchain to be installed via rustup (optional)
|
|
57
|
+
# You can also set the env var `RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN=true`
|
|
58
|
+
r.force_install_rust_toolchain = "stable"
|
|
59
|
+
|
|
60
|
+
# Clean up the target/ dir after `gem install` to reduce bloat (optional)
|
|
61
|
+
r.clean_after_install = false # default: true if invoked by rubygems
|
|
62
|
+
|
|
63
|
+
# Auto-install Rust toolchain if not present on "gem install" (optional)
|
|
64
|
+
r.auto_install_rust_toolchain = false # default: true if invoked by rubygems
|
|
65
|
+
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Tips and Tricks
|
|
69
|
+
|
|
70
|
+
- When using `rake-compiler` to build your gem, you can use the `RB_SYS_CARGO_PROFILE` environment variable to set the
|
|
71
|
+
Cargo profile (i.e. `release` or `dev`).
|
|
72
|
+
|
|
73
|
+
- You can pass Cargo arguments to `rake-compiler` like so: `rake compile -- --verbose`
|
|
74
|
+
|
|
75
|
+
- It's possible to force an installation of a Rust toolchain by setting the `RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN`
|
|
76
|
+
environment variable. This will install [rustup](https://rustup.rs/) and [cargo](https://crates.io/) in the build
|
|
77
|
+
directory, so the end user does not have to have Rust pre-installed. Ideally, this should be a last resort, as it's
|
|
78
|
+
better to already have the toolchain installed on your system.
|
|
79
|
+
|
|
80
|
+
## Troubleshooting
|
|
81
|
+
|
|
82
|
+
### Libclang issues
|
|
83
|
+
|
|
84
|
+
If you see an error like this:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
thread 'main' panicked at 'Unable to find libclang: "couldn't find any valid shared libraries matching: \['libclang.so', 'libclang-*.so', 'libclang.so.*', 'libclang-*.so.*'\], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: \[\])"'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This means that bindgen is having issues finding a usable version of libclang. An easy way to fix this is to install the
|
|
91
|
+
[`libclang` gem](https://github.com/oxidize-rb/libclang-rb), which will install a pre-built version of libclang for you.
|
|
92
|
+
`rb_sys` will automatically detect this gem and use it.
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
# Gemfile
|
|
96
|
+
|
|
97
|
+
gem "libclang", "~> 14.0.6"
|
|
98
|
+
```
|
data/exe/rb-sys-dock
CHANGED
|
@@ -1,82 +1,61 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
+
|
|
3
5
|
require "optparse"
|
|
6
|
+
require "open3"
|
|
4
7
|
require "rb_sys/version"
|
|
5
8
|
require "rb_sys/toolchain_info"
|
|
9
|
+
require "rb_sys/cargo/metadata"
|
|
10
|
+
require "rb_sys/util/logger"
|
|
6
11
|
require "fileutils"
|
|
7
12
|
require "tmpdir"
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
OPTIONS = {
|
|
15
|
+
docker_platform: "linux/amd64",
|
|
16
|
+
version: RbSys::VERSION,
|
|
17
|
+
directory: Dir.pwd
|
|
11
18
|
}
|
|
12
19
|
|
|
13
|
-
def
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
["❌", "\e[1;31m"]
|
|
17
|
-
when :warn
|
|
18
|
-
["⚠️", "\e[1;33m"]
|
|
19
|
-
when :info
|
|
20
|
-
["ℹ️", "\e[1;37m"]
|
|
21
|
-
when :notice
|
|
22
|
-
["🐳", "\e[1;34m"]
|
|
23
|
-
when :trace
|
|
24
|
-
return unless ENV["LOG_LEVEL"] == "trace"
|
|
25
|
-
|
|
26
|
-
["🔍", "\e[1;2m"]
|
|
27
|
-
else raise "Unknown log level: #{level.inspect}"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
emoji_opt = if emoji.is_a?(String)
|
|
31
|
-
emoji + " "
|
|
32
|
-
elsif emoji
|
|
33
|
-
emoji_opt + " "
|
|
34
|
-
end
|
|
20
|
+
def cargo_metadata
|
|
21
|
+
@cargo_metadata ||= RbSys::Cargo::Metadata.new("rb-sys-dock", deps: true)
|
|
22
|
+
end
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
def logger
|
|
25
|
+
return @logger if @logger
|
|
38
26
|
|
|
39
|
-
io.
|
|
27
|
+
io = ARGV.include?("--quiet") ? File.open(File::NULL, "w") : $stderr
|
|
28
|
+
@logger ||= RbSys::Util::Logger.new(io: io)
|
|
40
29
|
end
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
OptionParser.new do |opts|
|
|
32
|
+
opts.banner = <<~MSG
|
|
33
|
+
Usage: rb-sys-dock [OPTIONS] [COMMAND]
|
|
44
34
|
|
|
45
|
-
|
|
46
|
-
end
|
|
35
|
+
A CLI to facillitate building Ruby on Rust extensions using Docker.
|
|
47
36
|
|
|
48
|
-
|
|
49
|
-
log(:trace, "Running command: $ #{cmd}")
|
|
50
|
-
stdout, stderr, status = Open3.capture3(cmd)
|
|
37
|
+
Examples:
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
else
|
|
55
|
-
log(:error, "Error running command: $ #{cmd}")
|
|
56
|
-
warn(stderr)
|
|
57
|
-
exit(status.exitstatus)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
39
|
+
Build for Linux (x86_64)
|
|
40
|
+
$ rb-sys-dock --platform x86_64-linux --build
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
|
|
42
|
+
Build for macOS (Ruby 3.1 and 3.2)
|
|
43
|
+
$ rb-sys-dock -p arm64-darwin --ruby-versions 3.1,3.2 --build
|
|
63
44
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
log(:trace, "Could not find docker command, trying podman")
|
|
45
|
+
Enter a shell
|
|
46
|
+
$ rb-sys-dock --list-platforms
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@default_docker_command = "podman"
|
|
71
|
-
stdout
|
|
72
|
-
rescue Errno::ENOENT
|
|
73
|
-
log(:error, "Could not find docker or podman command, please install one of them")
|
|
74
|
-
exit(1)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
48
|
+
Run a command in the container with a specific directory mounted
|
|
49
|
+
$ rb-sys-dock -p x64-mingw-ucrt -d /tmp/mygem -- "env | grep RUBY"
|
|
77
50
|
|
|
78
|
-
|
|
79
|
-
|
|
51
|
+
List all supported platforms
|
|
52
|
+
$ rb-sys-dock --list-platforms
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
MSG
|
|
56
|
+
|
|
57
|
+
opts.on("--quiet", "Prints no logging output") do
|
|
58
|
+
end
|
|
80
59
|
|
|
81
60
|
opts.on("-v", "--version", "Prints version") do
|
|
82
61
|
require "rb_sys/version"
|
|
@@ -84,6 +63,10 @@ OptionParser.new do |opts|
|
|
|
84
63
|
exit
|
|
85
64
|
end
|
|
86
65
|
|
|
66
|
+
opts.on("--build", "Run the default command to cross-compile a gem") do
|
|
67
|
+
OPTIONS[:build] = true
|
|
68
|
+
end
|
|
69
|
+
|
|
87
70
|
opts.on("-p", "--platform PLATFORM", "Platform to build for (i.e. x86_64-linux)") do |p|
|
|
88
71
|
toolchain_info = begin
|
|
89
72
|
RbSys::ToolchainInfo.new(p)
|
|
@@ -91,42 +74,40 @@ OptionParser.new do |opts|
|
|
|
91
74
|
supported_list = RbSys::ToolchainInfo.all
|
|
92
75
|
supported_list.select!(&:supported?)
|
|
93
76
|
list = supported_list.map { |p| "- #{p} (#{p.rust_target})" }.join("\n")
|
|
94
|
-
|
|
77
|
+
logger.error("Platform #{p} is not supported, please use one of:\n\n#{list}")
|
|
95
78
|
exit(1)
|
|
96
79
|
end
|
|
97
80
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
opts.on("--latest", "Use the latest version of the Docker image") do
|
|
103
|
-
log(:notice, "Using latest version of the Docker image", emoji: "🆕")
|
|
104
|
-
options[:version] = "latest"
|
|
105
|
-
options[:no_cache] = true
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
opts.on("--list-platforms", "--list", "List all supported platforms") do
|
|
109
|
-
log(:notice, "Supported platforms listed below:")
|
|
110
|
-
|
|
111
|
-
RbSys::ToolchainInfo.supported.each do |p|
|
|
112
|
-
log(:info, "- #{p} (#{p.rust_target})", emoji: false, io: $stdout)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
exit(0)
|
|
81
|
+
OPTIONS[:platform] = p
|
|
82
|
+
OPTIONS[:toolchain_info] = toolchain_info
|
|
116
83
|
end
|
|
117
84
|
|
|
118
|
-
opts.on("--ruby-versions LIST", "List all supported Ruby versions") do |arg|
|
|
119
|
-
log(:notice, "Requested Ruby versions: #{arg}")
|
|
120
|
-
|
|
85
|
+
opts.on("-r", "--ruby-versions LIST", "List all supported Ruby versions") do |arg|
|
|
121
86
|
vers = arg.split(/[^0-9.]/).map do |v|
|
|
122
87
|
parts = v.split(".")
|
|
123
88
|
parts[2] = "0" if parts[2].nil?
|
|
124
89
|
parts.join(".")
|
|
125
90
|
end
|
|
126
91
|
|
|
92
|
+
OPTIONS[:ruby_versions] = vers
|
|
93
|
+
|
|
94
|
+
logger.info("Building for Ruby requested versions: #{vers}")
|
|
95
|
+
|
|
127
96
|
ENV["RUBY_CC_VERSION"] = vers.join(":")
|
|
128
97
|
end
|
|
129
98
|
|
|
99
|
+
opts.on("--tag TAG", "Use a specific version of the Docker image") do |tag|
|
|
100
|
+
logger.info("Using version #{tag} of the Docker image")
|
|
101
|
+
OPTIONS[:version] = tag
|
|
102
|
+
OPTIONS[:no_cache] = tag == "latest"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
opts.on("--list-platforms", "--list", "List all supported platforms") do
|
|
106
|
+
logger.info("Supported platforms listed below:")
|
|
107
|
+
list_platforms
|
|
108
|
+
exit(0)
|
|
109
|
+
end
|
|
110
|
+
|
|
130
111
|
opts.on("-h", "--help", "Prints this help") do
|
|
131
112
|
puts opts
|
|
132
113
|
exit
|
|
@@ -135,14 +116,60 @@ OptionParser.new do |opts|
|
|
|
135
116
|
opts.on("-V", "--verbose", "Prints verbose output") do
|
|
136
117
|
ENV["LOG_LEVEL"] = "trace"
|
|
137
118
|
ENV["VERBOSE"] = "1"
|
|
138
|
-
|
|
119
|
+
logger.level = :trace
|
|
120
|
+
OPTIONS[:verbose] = true
|
|
139
121
|
end
|
|
140
122
|
|
|
141
|
-
opts.on("--
|
|
142
|
-
|
|
123
|
+
opts.on("--mount-toolchains", "Mount local Rustup toolchain (instead of pre-installed from Docker container)") do
|
|
124
|
+
OPTIONS[:mount_rustup_toolchains] = true
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
opts.on("-d", "--directory DIR", "Directory to run the command in") do |val|
|
|
128
|
+
OPTIONS[:directory] = File.expand_path(val)
|
|
143
129
|
end
|
|
144
130
|
end.parse!
|
|
145
131
|
|
|
132
|
+
def list_platforms
|
|
133
|
+
RbSys::ToolchainInfo.supported.each do |p|
|
|
134
|
+
old = logger.io
|
|
135
|
+
logger.io = $stdout
|
|
136
|
+
puts "- #{p.platform}"
|
|
137
|
+
ensure
|
|
138
|
+
logger.io = old
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def default_docker_command
|
|
143
|
+
return @default_docker_command if defined?(@default_docker_command)
|
|
144
|
+
|
|
145
|
+
@default_docker_command = ENV.fetch("DOCKER") do
|
|
146
|
+
if !(docker = `which docker`).empty?
|
|
147
|
+
docker.strip
|
|
148
|
+
elsif !(podman = `which podman`).empty?
|
|
149
|
+
podman.strip
|
|
150
|
+
else
|
|
151
|
+
logger.fatal("Could not find docker or podman command, please install one of them")
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def run_command!(*cmd)
|
|
157
|
+
logger.trace("Running command:\n\t$ #{cmd.join(" ")}")
|
|
158
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
|
159
|
+
|
|
160
|
+
if status.success?
|
|
161
|
+
stdout
|
|
162
|
+
else
|
|
163
|
+
logger.error("Error running command: $ #{cmd}")
|
|
164
|
+
warn(stderr)
|
|
165
|
+
exit(status.exitstatus)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def docker(cmd)
|
|
170
|
+
run_command!("#{default_docker_command} #{cmd}")
|
|
171
|
+
end
|
|
172
|
+
|
|
146
173
|
def determine_cache_dir
|
|
147
174
|
return ENV["RB_SYS_DOCK_CACHE_DIR"] if ENV["RB_SYS_DOCK_CACHE_DIR"]
|
|
148
175
|
return File.join(ENV["XDG_CACHE_HOME"], "rb-sys-dock") if ENV["XDG_CACHE_HOME"]
|
|
@@ -172,53 +199,93 @@ def mount_cargo_registry
|
|
|
172
199
|
end
|
|
173
200
|
|
|
174
201
|
dir = File.join("registry")
|
|
175
|
-
|
|
202
|
+
logger.trace("Mounting cargo registry dir: #{dir}")
|
|
176
203
|
FileUtils.mkdir_p(dir)
|
|
177
204
|
|
|
178
|
-
|
|
205
|
+
mount_shared_bind_dir(File.join(local_registry_dir, dir), File.join("/usr/local/cargo", dir))
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def mount_rustup_toolchains
|
|
209
|
+
return unless OPTIONS[:mount_rustup_toolchains]
|
|
210
|
+
|
|
211
|
+
local_rustup_dir = if OPTIONS[:mount_rustup_toolchains].is_a?(String)
|
|
212
|
+
OPTIONS[:mount_rustup_toolchains]
|
|
213
|
+
elsif ENV["RUSTUP_HOME"]
|
|
214
|
+
ENV["RUSTUP_HOME"]
|
|
215
|
+
elsif File.exist?(rustup_home = File.join(ENV["HOME"], ".rustup"))
|
|
216
|
+
rustup_home
|
|
217
|
+
else
|
|
218
|
+
logger.fatal("Could not find Rustup home directory, please set RUSTUP_HOME")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
logger.info("Mounting rustup toolchains from #{local_rustup_dir}")
|
|
222
|
+
|
|
223
|
+
target_triple = OPTIONS[:toolchain_info].rust_target
|
|
224
|
+
dkr_triple = "x86_64-unknown-linux-gnu"
|
|
225
|
+
dkr_toolchain = "stable-#{dkr_triple}"
|
|
226
|
+
dkr_toolchain_dir = "/usr/local/rustup/toolchains/#{dkr_toolchain}"
|
|
227
|
+
installed_toolchains = Dir.glob(File.join(local_rustup_dir, "toolchains", "*")).map { |f| File.basename(f) }
|
|
228
|
+
has_host_toolchain = installed_toolchains.any? { |t| t.end_with?(dkr_toolchain) }
|
|
229
|
+
|
|
230
|
+
if !has_host_toolchain
|
|
231
|
+
logger.info("Installing default toolchain for docker image (#{dkr_toolchain})")
|
|
232
|
+
run_command!("rustup", "toolchain", "add", dkr_toolchain, "--force-non-host")
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
has_target = run_command!("rustup target list --installed --toolchain #{dkr_toolchain}").include?(target_triple)
|
|
236
|
+
|
|
237
|
+
if !has_target
|
|
238
|
+
logger.info("Installing target for docker image (#{target_triple})")
|
|
239
|
+
run_command!("rustup", "target", "add", target_triple, "--toolchain", dkr_toolchain)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
volume("#{local_rustup_dir}/toolchains/#{dkr_toolchain}", dkr_toolchain_dir, mode: "z,ro")
|
|
179
243
|
end
|
|
180
244
|
|
|
181
245
|
def volume(src, dest, mode: "rw")
|
|
182
246
|
"--volume #{src}:#{dest}:rw"
|
|
183
247
|
end
|
|
184
248
|
|
|
185
|
-
def mount_bundle_cache
|
|
186
|
-
dir = File.join(cache_dir,
|
|
249
|
+
def mount_bundle_cache
|
|
250
|
+
dir = File.join(cache_dir, ruby_platform, "bundle")
|
|
187
251
|
bundle_path = File.join(docker_tmp, "bundle")
|
|
188
252
|
FileUtils.mkdir_p(dir)
|
|
189
|
-
|
|
253
|
+
logger.trace("Mounting bundle cache: #{dir}")
|
|
190
254
|
|
|
191
255
|
"#{volume(dir, bundle_path)} -e BUNDLE_PATH=#{bundle_path.inspect}"
|
|
192
256
|
end
|
|
193
257
|
|
|
194
|
-
def tmp_target_dir
|
|
258
|
+
def tmp_target_dir
|
|
195
259
|
return @tmp_target_dir if defined?(@tmp_target_dir)
|
|
196
260
|
|
|
197
|
-
dir = File.join(
|
|
261
|
+
dir = File.join(working_directory, "tmp", "rb-sys-dock", ruby_platform, "target")
|
|
198
262
|
FileUtils.mkdir_p(dir)
|
|
199
263
|
@tmp_target_dir = dir
|
|
200
264
|
end
|
|
201
265
|
|
|
202
|
-
def
|
|
203
|
-
|
|
266
|
+
def working_directory
|
|
267
|
+
OPTIONS.fetch(:directory)
|
|
204
268
|
end
|
|
205
269
|
|
|
206
|
-
def
|
|
270
|
+
def mount_target_dir
|
|
271
|
+
"-v #{tmp_target_dir}:#{File.join(working_directory, "target")}"
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def mount_command_history
|
|
207
275
|
return unless $stdin.tty?
|
|
208
276
|
|
|
209
|
-
history_dir = File.join(cache_dir,
|
|
277
|
+
history_dir = File.join(cache_dir, OPTIONS.fetch(:platform), "commandhistory")
|
|
210
278
|
FileUtils.mkdir_p(history_dir)
|
|
211
279
|
"-v #{history_dir}:#{File.join(docker_tmp, "commandhistory")}"
|
|
212
280
|
end
|
|
213
281
|
|
|
214
|
-
def default_command_to_run(input_args
|
|
282
|
+
def default_command_to_run(input_args)
|
|
215
283
|
input_cmd = input_args.empty? ? "true" : input_args.join(" ")
|
|
216
284
|
|
|
217
|
-
if
|
|
285
|
+
if OPTIONS[:build]
|
|
218
286
|
with_bundle = +"test -f Gemfile && bundle install && #{input_cmd} && bundle exec rake native:$RUBY_TARGET gem"
|
|
219
287
|
without_bundle = "#{input_cmd} && rake native:$RUBY_TARGET gem"
|
|
220
|
-
|
|
221
|
-
log(:notice, " $ rake native:#{options[:toolchain_info].platform} gem")
|
|
288
|
+
logger.info("Running default build command (rake native:#{ruby_platform} gem)")
|
|
222
289
|
"bash -c '(#{with_bundle}) || (#{without_bundle})'"
|
|
223
290
|
else
|
|
224
291
|
input_args.empty? ? "bash" : "bash -c '#{input_args.join(" ")}'"
|
|
@@ -242,11 +309,27 @@ def interactive?(input_args)
|
|
|
242
309
|
$stdin.tty?
|
|
243
310
|
end
|
|
244
311
|
|
|
245
|
-
def
|
|
246
|
-
"--mount type=bind,source=#{
|
|
312
|
+
def mount_shared_bind_dir(src, dest)
|
|
313
|
+
"--mount type=bind,source=#{src},destination=#{dest},readonly=false"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def mount_tmp_dir
|
|
317
|
+
"--mount type=bind,source=#{Dir.mktmpdir},destination=#{working_directory}/tmp/#{ruby_platform},readonly=false"
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def toolchain_info
|
|
321
|
+
@toolchain_info ||= OPTIONS.fetch(:toolchain_info) do
|
|
322
|
+
logger.error("Could not determine ruby platform, please set ruby platform with --platform to one of:")
|
|
323
|
+
list_platforms
|
|
324
|
+
logger.fatal("Exiting...")
|
|
325
|
+
end
|
|
247
326
|
end
|
|
248
327
|
|
|
249
|
-
def
|
|
328
|
+
def ruby_platform
|
|
329
|
+
@ruby_platform ||= toolchain_info.platform
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def rcd(input_args)
|
|
250
333
|
wrapper_command = []
|
|
251
334
|
wrapper_command << "sigfw" unless interactive?(input_args)
|
|
252
335
|
wrapper_command << "runas"
|
|
@@ -256,12 +339,14 @@ def rcd(input_args, options)
|
|
|
256
339
|
|
|
257
340
|
cmd = <<~SH
|
|
258
341
|
#{default_docker_command} run \
|
|
259
|
-
|
|
260
|
-
#{
|
|
261
|
-
#{
|
|
342
|
+
--platform #{OPTIONS.fetch(:docker_platform)} \
|
|
343
|
+
-v #{working_directory}:#{working_directory} \
|
|
344
|
+
#{mount_tmp_dir} \
|
|
345
|
+
#{mount_target_dir} \
|
|
262
346
|
#{mount_cargo_registry} \
|
|
263
|
-
#{
|
|
264
|
-
#{
|
|
347
|
+
#{mount_rustup_toolchains} \
|
|
348
|
+
#{mount_bundle_cache} \
|
|
349
|
+
#{mount_command_history} \
|
|
265
350
|
#{user_mapping} \
|
|
266
351
|
-e GEM_PRIVATE_KEY_PASSPHRASE \
|
|
267
352
|
-e ftp_proxy \
|
|
@@ -269,52 +354,64 @@ def rcd(input_args, options)
|
|
|
269
354
|
-e https_proxy \
|
|
270
355
|
-e RCD_HOST_RUBY_PLATFORM=#{RbConfig::CONFIG["arch"]} \
|
|
271
356
|
-e RCD_HOST_RUBY_VERSION=#{RUBY_VERSION} \
|
|
357
|
+
-e RUSTUP_PERMIT_COPY_RENAME=true \
|
|
272
358
|
-e RCD_IMAGE \
|
|
273
359
|
-e RB_SYS_DOCK_TMPDIR="/tmp/rb-sys-dock" \
|
|
274
|
-
-e RB_SYS_CARGO_TARGET_DIR=#{tmp_target_dir
|
|
360
|
+
-e RB_SYS_CARGO_TARGET_DIR=#{tmp_target_dir.inspect} \
|
|
275
361
|
#{ENV["RUBY_CC_VERSION"] ? "-e RUBY_CC_VERSION=#{ENV["RUBY_CC_VERSION"]}" : ""} \
|
|
276
362
|
-e RAKEOPT \
|
|
277
363
|
-e TERM \
|
|
278
|
-
-
|
|
279
|
-
-w #{Dir.pwd} \
|
|
364
|
+
-w #{working_directory} \
|
|
280
365
|
--rm \
|
|
281
366
|
--interactive \
|
|
282
367
|
#{docker_options.join(" ")} \
|
|
283
368
|
#{ENV.fetch("RCD_IMAGE")} \
|
|
284
369
|
#{wrapper_command.join(" ")} \
|
|
285
|
-
#{default_command_to_run(input_args
|
|
370
|
+
#{default_command_to_run(input_args)}
|
|
286
371
|
SH
|
|
287
372
|
|
|
288
|
-
|
|
373
|
+
cmd.gsub!(/\s+/, " ")
|
|
374
|
+
|
|
375
|
+
logger.trace("Running command:\n\t$ #{cmd}")
|
|
289
376
|
|
|
290
377
|
exec(cmd)
|
|
291
378
|
end
|
|
292
379
|
|
|
293
|
-
def download_image
|
|
380
|
+
def download_image
|
|
294
381
|
image = ENV.fetch("RCD_IMAGE")
|
|
295
382
|
|
|
296
|
-
if docker("images -q #{image}").strip.empty? ||
|
|
383
|
+
if docker("images -q #{image}").strip.empty? || OPTIONS[:no_cache]
|
|
297
384
|
# Nicely formatted message that we are downloading the image which might take awhile
|
|
298
|
-
|
|
299
|
-
docker("pull #{image} --quiet > /dev/null")
|
|
385
|
+
logger.info("Downloading container #{image.inspect}, this might take awhile...")
|
|
386
|
+
docker("pull #{image} --platform #{OPTIONS[:docker_platform]} --quiet > /dev/null")
|
|
300
387
|
end
|
|
301
388
|
end
|
|
302
389
|
|
|
303
|
-
def log_some_useful_info
|
|
304
|
-
return if
|
|
390
|
+
def log_some_useful_info
|
|
391
|
+
return if OPTIONS[:build]
|
|
305
392
|
|
|
306
393
|
if ARGV.empty?
|
|
307
|
-
|
|
394
|
+
logger.info("Entering shell in Docker container #{ENV["RCD_IMAGE"].inspect}")
|
|
308
395
|
else
|
|
309
|
-
|
|
396
|
+
logger.info("Running command #{ARGV.inspect} in Docker container #{ENV["RCD_IMAGE"].inspect}")
|
|
310
397
|
end
|
|
311
398
|
end
|
|
312
399
|
|
|
313
|
-
def set_env
|
|
314
|
-
ENV["RCD_IMAGE"] ||= "rbsys/#{
|
|
400
|
+
def set_env
|
|
401
|
+
ENV["RCD_IMAGE"] ||= "rbsys/#{ruby_platform}:#{OPTIONS[:version]}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def lint_rb_sys
|
|
405
|
+
cargo_version = cargo_metadata.rb_sys_version
|
|
406
|
+
return if cargo_version == RbSys::VERSION
|
|
407
|
+
logger.warn("Cargo rb-sys version (#{cargo_version}) does not match Ruby gem version (#{RbSys::VERSION})")
|
|
408
|
+
rescue => e
|
|
409
|
+
logger.warn("Could not determine Cargo rb-sys version")
|
|
410
|
+
logger.trace("Error was: #{e.inspect}")
|
|
315
411
|
end
|
|
316
412
|
|
|
317
|
-
set_env
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
413
|
+
set_env
|
|
414
|
+
lint_rb_sys
|
|
415
|
+
download_image
|
|
416
|
+
log_some_useful_info
|
|
417
|
+
rcd(ARGV)
|
|
@@ -9,35 +9,93 @@ module RbSys
|
|
|
9
9
|
class Metadata
|
|
10
10
|
attr_reader :name
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Initializes a new Cargo::Metadata instance.
|
|
13
|
+
#
|
|
14
|
+
# @param name [String] the name of the Cargo project
|
|
15
|
+
def initialize(name, deps: false)
|
|
13
16
|
raise ArgumentError, "name must be a String" unless name.is_a?(String)
|
|
14
17
|
|
|
15
18
|
@name = name
|
|
19
|
+
@cargo_metadata = nil
|
|
20
|
+
@package_metadata = nil
|
|
21
|
+
@deps = deps
|
|
16
22
|
end
|
|
17
23
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
# Returns the path where the Cargo project's Cargo.toml is located.
|
|
25
|
+
#
|
|
26
|
+
# @return [String]
|
|
27
|
+
def manifest_directory
|
|
28
|
+
@manifest_directory ||= File.dirname(manifest_path)
|
|
23
29
|
end
|
|
24
30
|
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
# Returns the target directory for the Cargo project.
|
|
32
|
+
#
|
|
33
|
+
# @return [String]
|
|
34
|
+
def target_directory
|
|
35
|
+
cargo_metadata.fetch("target_directory")
|
|
30
36
|
end
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
# Returns the workspace root for the Cargo project.
|
|
39
|
+
#
|
|
40
|
+
# @return [String]
|
|
41
|
+
def workspace_root
|
|
42
|
+
cargo_metadata.fetch("workspace_root")
|
|
43
|
+
end
|
|
33
44
|
|
|
34
|
-
|
|
45
|
+
# Returns the workspace members for the Cargo project.
|
|
46
|
+
#
|
|
47
|
+
# @return [Array<Hash>]
|
|
48
|
+
def packages
|
|
49
|
+
cargo_metadata.fetch("packages")
|
|
50
|
+
end
|
|
35
51
|
|
|
36
|
-
# Returns the path
|
|
52
|
+
# Returns the path to the package's Cargo.toml.
|
|
37
53
|
#
|
|
38
54
|
# @return [String]
|
|
39
|
-
def
|
|
40
|
-
|
|
55
|
+
def manifest_path
|
|
56
|
+
package_metadata.fetch("manifest_path")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns the package's version.
|
|
60
|
+
#
|
|
61
|
+
# @return [String]
|
|
62
|
+
def version
|
|
63
|
+
package_metadata.fetch("version")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns the package's id.
|
|
67
|
+
#
|
|
68
|
+
# @return [String]
|
|
69
|
+
def id
|
|
70
|
+
package_metadata.fetch("id")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns the package's Rust edition.
|
|
74
|
+
#
|
|
75
|
+
# @return [String]
|
|
76
|
+
def edition
|
|
77
|
+
package_metadata.fetch("edition")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the package's features.
|
|
81
|
+
#
|
|
82
|
+
# @return [Array<String>]
|
|
83
|
+
def features
|
|
84
|
+
package_metadata.fetch("features")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns the package's custom metadata.
|
|
88
|
+
#
|
|
89
|
+
# @return [Hash]
|
|
90
|
+
def metadata
|
|
91
|
+
package_metadata.fetch("metadata")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns the rb-sys version, if any.
|
|
95
|
+
def rb_sys_version
|
|
96
|
+
pkg = packages.find { |p| p.fetch("name") == "rb-sys" }
|
|
97
|
+
return unless pkg
|
|
98
|
+
pkg["version"]
|
|
41
99
|
end
|
|
42
100
|
|
|
43
101
|
private
|
|
@@ -55,11 +113,15 @@ module RbSys
|
|
|
55
113
|
|
|
56
114
|
::Gem.load_yaml
|
|
57
115
|
cargo = ENV["CARGO"] || "cargo"
|
|
58
|
-
args = ["metadata", "--
|
|
59
|
-
|
|
60
|
-
|
|
116
|
+
args = ["metadata", "--format-version", "1"]
|
|
117
|
+
args << "--no-deps" unless @deps
|
|
118
|
+
out, stderr, status = Open3.capture3(cargo, *args)
|
|
119
|
+
raise "exited with non-zero status (#{status})" unless status.success?
|
|
120
|
+
data = Gem::SafeYAML.safe_load(out)
|
|
121
|
+
raise "metadata must be a Hash" unless data.is_a?(Hash)
|
|
122
|
+
@cargo_metadata = data
|
|
61
123
|
rescue => err
|
|
62
|
-
raise CargoMetadataError.new(err, stderr
|
|
124
|
+
raise CargoMetadataError.new(err, stderr)
|
|
63
125
|
end
|
|
64
126
|
end
|
|
65
127
|
end
|
data/lib/rb_sys/error.rb
CHANGED
|
@@ -19,18 +19,24 @@ module RbSys
|
|
|
19
19
|
|
|
20
20
|
# Raised when Cargo metadata cannot be parsed.
|
|
21
21
|
class CargoMetadataError < Error
|
|
22
|
-
def initialize(err, stderr
|
|
22
|
+
def initialize(err, stderr)
|
|
23
23
|
msg = <<~MSG.chomp.tr("\n", " ")
|
|
24
|
-
Could not
|
|
25
|
-
is valid. The error was: #{err}
|
|
24
|
+
Could not infer Rust crate information using `cargo metadata`.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Original error was:
|
|
27
|
+
#{err.class}: #{err.message}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
Things to check:
|
|
30
|
+
- Check that your ext/*/Cargo.toml at is valid
|
|
31
|
+
- If you are using a workspace, make sure you are the root Cargo.toml exists
|
|
32
|
+
- Make sure `cargo` is installed and in your PATH
|
|
32
33
|
MSG
|
|
33
34
|
|
|
35
|
+
if !stderr.empty?
|
|
36
|
+
indented_stderr = stderr.lines.map { |line| " #{line}" }.join
|
|
37
|
+
msg << "Stderr from `cargo metadata` was:\n#{indented_stderr}"
|
|
38
|
+
end
|
|
39
|
+
|
|
34
40
|
super(msg)
|
|
35
41
|
end
|
|
36
42
|
end
|
data/lib/rb_sys/extensiontask.rb
CHANGED
|
@@ -4,7 +4,7 @@ require_relative "error"
|
|
|
4
4
|
begin
|
|
5
5
|
require "rake/extensiontask"
|
|
6
6
|
rescue LoadError
|
|
7
|
-
abort "Please install rake-compiler to use this
|
|
7
|
+
abort "Please install rake-compiler to use this feature"
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
module RbSys
|
|
@@ -22,8 +22,9 @@ module RbSys
|
|
|
22
22
|
# @param gem_spec [Gem::Specification] the gem specification to build (needed for cross-compiling)
|
|
23
23
|
# @return [Rake::ExtensionTask]
|
|
24
24
|
class ExtensionTask < Rake::ExtensionTask
|
|
25
|
-
def init(name = nil, gem_spec =
|
|
26
|
-
super
|
|
25
|
+
def init(name = nil, gem_spec = :undefined)
|
|
26
|
+
super(name, lint_gem_spec(name, gem_spec))
|
|
27
|
+
|
|
27
28
|
@orginal_ext_dir = @ext_dir
|
|
28
29
|
@ext_dir = cargo_metadata.manifest_directory
|
|
29
30
|
@source_pattern = nil
|
|
@@ -46,6 +47,8 @@ module RbSys
|
|
|
46
47
|
def define
|
|
47
48
|
super
|
|
48
49
|
define_env_tasks
|
|
50
|
+
|
|
51
|
+
CLEAN.include(target_directory) if defined?(CLEAN)
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
def cargo_metadata
|
|
@@ -118,5 +121,34 @@ module RbSys
|
|
|
118
121
|
desc 'Compile the native Rust extension with the "release" profile'
|
|
119
122
|
task "compile:release" => ["rb_sys:env:release", "compile"]
|
|
120
123
|
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def lint_gem_spec(name, gs)
|
|
128
|
+
gem_spec = case gs
|
|
129
|
+
when :undefined
|
|
130
|
+
return
|
|
131
|
+
when Gem::Specification
|
|
132
|
+
gs
|
|
133
|
+
when String
|
|
134
|
+
Gem::Specification.load(gem_spec) || raise(ArgumentError, "Unable to load gemspec from file #{gs.inspect}")
|
|
135
|
+
else
|
|
136
|
+
raise ArgumentError, "gem_spec must be a Gem::Specification, got #{gs.class}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
gem_spec.files.each do |f|
|
|
140
|
+
if /\.(dll|so|dylib|lib|bundle)$/.match?(f)
|
|
141
|
+
warn "⚠️ gemspec includes native artifact (#{f}), please remove it."
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
if (gem_crate_name = gem_spec.metadata["cargo_crate_name"])
|
|
146
|
+
if name != gem_crate_name
|
|
147
|
+
warn "⚠️ cargo_crate_name (#{gem_crate_name}) does not match extension task crate name (#{name})"
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
gem_spec
|
|
152
|
+
end
|
|
121
153
|
end
|
|
122
154
|
end
|
data/lib/rb_sys/mkmf.rb
CHANGED
|
@@ -59,6 +59,7 @@ module RbSys
|
|
|
59
59
|
#{conditional_assign("CARGO", "cargo")}
|
|
60
60
|
#{conditional_assign("CARGO_BUILD_TARGET", builder.target)}
|
|
61
61
|
#{conditional_assign("SOEXT", builder.so_ext)}
|
|
62
|
+
#{try_load_bundled_libclang(builder)}
|
|
62
63
|
|
|
63
64
|
# Determine the prefix Cargo uses for the lib.
|
|
64
65
|
#{if_neq_stmt("$(SOEXT)", "dll")}
|
|
@@ -245,7 +246,6 @@ module RbSys
|
|
|
245
246
|
\t$(Q) curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --no-modify-path --profile $(RB_SYS_RUSTUP_PROFILE) --default-toolchain none -y
|
|
246
247
|
\t$(Q) rustup toolchain install $(RB_SYS_DEFAULT_TOOLCHAIN) --profile $(RB_SYS_RUSTUP_PROFILE)
|
|
247
248
|
\t$(Q) rustup default $(RB_SYS_DEFAULT_TOOLCHAIN)
|
|
248
|
-
\t$(Q) rustup component add rustfmt
|
|
249
249
|
|
|
250
250
|
$(RUSTLIB): $(CARGO)
|
|
251
251
|
#{endif_stmt}
|
|
@@ -317,6 +317,26 @@ module RbSys
|
|
|
317
317
|
end
|
|
318
318
|
end
|
|
319
319
|
|
|
320
|
+
def try_load_bundled_libclang(_builder)
|
|
321
|
+
require "libclang"
|
|
322
|
+
assert_libclang_version_valid!
|
|
323
|
+
export_env("LIBCLANG_PATH", Libclang.libdir)
|
|
324
|
+
rescue LoadError
|
|
325
|
+
# If we can't load the bundled libclang, just continue
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def assert_libclang_version_valid!
|
|
329
|
+
libclang_version = Libclang.version
|
|
330
|
+
|
|
331
|
+
if libclang_version < Gem::Version.new("5.0.0")
|
|
332
|
+
raise "libclang version 5.0.0 or greater is required (current #{libclang_version})"
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
if libclang_version >= Gem::Version.new("15.0.0")
|
|
336
|
+
raise "libclang version > 14.0.0 or greater is required (current #{libclang_version})"
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
320
340
|
def set_cargo_profile(builder)
|
|
321
341
|
return assign_stmt("RB_SYS_CARGO_PROFILE", "release") if builder.rubygems_invoked?
|
|
322
342
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RbSys
|
|
4
|
+
module Util
|
|
5
|
+
class Logger
|
|
6
|
+
attr_accessor :io, :level
|
|
7
|
+
|
|
8
|
+
def initialize(io: $stderr, level: :info)
|
|
9
|
+
@io = ENV["GITHUB_ACTIONS"] ? $stdout : io
|
|
10
|
+
@level = level
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def error(message, **opts)
|
|
14
|
+
add(:error, message, **opts)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def warn(message, **opts)
|
|
18
|
+
add(:warn, message, **opts)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def info(message, **opts)
|
|
22
|
+
add(:info, message, **opts)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def notice(message, **opts)
|
|
26
|
+
add(:notice, message, **opts)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def trace(message, **opts)
|
|
30
|
+
return unless level == :trace
|
|
31
|
+
|
|
32
|
+
add(:trace, message, **opts)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def fatal(message, **opts)
|
|
36
|
+
error(message, **opts)
|
|
37
|
+
abort
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
LEVEL_STYLES = {
|
|
43
|
+
warn: ["⚠️", "\e[1;33m"],
|
|
44
|
+
error: ["❌", "\e[1;31m"],
|
|
45
|
+
notice: ["👋", "\e[1;37m"],
|
|
46
|
+
info: ["🐳", "\e[1;34m"],
|
|
47
|
+
trace: ["🔍", "\e[1;2m"]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if ENV["GITHUB_ACTIONS"]
|
|
51
|
+
def add(level, message, emoji: true)
|
|
52
|
+
emote, _ = LEVEL_STYLES.fetch(level.to_sym)
|
|
53
|
+
io.puts "::#{level}::#{emote} #{message}"
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
def add(level, message, emoji: true)
|
|
57
|
+
emoji_opt, shellcode = LEVEL_STYLES.fetch(level.to_sym)
|
|
58
|
+
|
|
59
|
+
emoji_opt = if emoji.is_a?(String)
|
|
60
|
+
emoji + " "
|
|
61
|
+
elsif emoji
|
|
62
|
+
emoji_opt + " "
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Escape the message for bash shell codes (e.g. \033[1;31m)
|
|
66
|
+
escaped = message.gsub("\\", "\\\\\\").gsub("\033", "\\033")
|
|
67
|
+
|
|
68
|
+
io.puts "#{shellcode}#{emoji_opt}#{escaped}\033[0m"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/rb_sys/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
���2��N���C�$�#d&>?��yZZv�_Il�3�/z��d7��Fo���{7B���J3Ql��:w� � �pVh���:
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rb_sys
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.65
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ian Ker-Seymer
|
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
|
30
30
|
Rl+ASkq2/1i07TkBpCf+2hq66+h/hx+/Y/KrUzXfe0jtvil0WESkJT2kqRqHWNhD
|
|
31
31
|
9GKBxaQlXokNDtWCm1/gl6cD8WRZ0N5S4ZGJT1FLLsA=
|
|
32
32
|
-----END CERTIFICATE-----
|
|
33
|
-
date: 2023-02-
|
|
33
|
+
date: 2023-02-13 00:00:00.000000000 Z
|
|
34
34
|
dependencies: []
|
|
35
35
|
description:
|
|
36
36
|
email:
|
|
@@ -40,8 +40,10 @@ executables:
|
|
|
40
40
|
extensions: []
|
|
41
41
|
extra_rdoc_files: []
|
|
42
42
|
files:
|
|
43
|
+
- ".yardopts"
|
|
43
44
|
- LICENSE-APACHE
|
|
44
45
|
- LICENSE-MIT
|
|
46
|
+
- README.md
|
|
45
47
|
- certs/ianks.pem
|
|
46
48
|
- exe/rb-sys-dock
|
|
47
49
|
- lib/rb_sys.rb
|
|
@@ -55,9 +57,9 @@ files:
|
|
|
55
57
|
- lib/rb_sys/mkmf/config.rb
|
|
56
58
|
- lib/rb_sys/toolchain_info.rb
|
|
57
59
|
- lib/rb_sys/toolchain_info/data.rb
|
|
60
|
+
- lib/rb_sys/util/logger.rb
|
|
58
61
|
- lib/rb_sys/version.rb
|
|
59
|
-
-
|
|
60
|
-
homepage: https://github.com/oxidize-rb/rb-sys
|
|
62
|
+
homepage: https://oxidize-rb.github.io/rb-sys/
|
|
61
63
|
licenses:
|
|
62
64
|
- MIT
|
|
63
65
|
- Apache-2.0
|
|
@@ -78,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
78
80
|
- !ruby/object:Gem::Version
|
|
79
81
|
version: '0'
|
|
80
82
|
requirements: []
|
|
81
|
-
rubygems_version: 3.4.
|
|
83
|
+
rubygems_version: 3.4.6
|
|
82
84
|
signing_key:
|
|
83
85
|
specification_version: 4
|
|
84
86
|
summary: Helpers for compiling Rust extensions for ruby
|
metadata.gz.sig
CHANGED
|
Binary file
|
data/sig/rb_sys.rbs
DELETED