rb_sys 0.9.64 → 0.9.65

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da8a462e7210f1746cca7dd9935d243b179176318aa766474fc33dd2de71227c
4
- data.tar.gz: 7cd4a0126f7240b2b58ee3338dceec912d1cd9de211adc55a6f4da320fa982cc
3
+ metadata.gz: 5dc9ecb59d4b2cc130afff772c740063ee2bdbf5bdf15fb866aa6dcbb501d396
4
+ data.tar.gz: b9c2c65ef48e0c5400ea857bb75ad9ec85ffac300a4290bc6f20ef00ca5e8163
5
5
  SHA512:
6
- metadata.gz: be81aba075a717c61a156cfcfafba1b9e7b36a33a045a2f04372b1c8244dd4280c0ebcc113fdc5c468bf72e49b6aaa8eff8d20784706ac779bab80e64d09ae04
7
- data.tar.gz: 3fa8cb0393b6cbbd53cba685b8616e5b747556ea583b8e943ec54b93a938b6b0f6610768c545e28076eb9806afb92108e1bdf6e0e2f9d78b6cdaf05666fa6bd9
6
+ metadata.gz: 3c4acd2a28480da0b8adb18a48a806354afae12d963b9394f6ce9bd41f89c703a27dbe9a6bc52136f897ad7e64ccba70c9bbfd4231a9b209964d130dc703d8ad
7
+ data.tar.gz: 849c5b3fd8209dfe41b6a5efc0dbd06d6760e849b32cd0182915f9e1d5e011885ba64d56ef7c8f8ed286094ba4efaaec2ad5ffa1134690579223ae826e81ba54
checksums.yaml.gz.sig CHANGED
Binary file
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
- options = {
10
- version: RbSys::VERSION
14
+ OPTIONS = {
15
+ docker_platform: "linux/amd64",
16
+ version: RbSys::VERSION,
17
+ directory: Dir.pwd
11
18
  }
12
19
 
13
- def log(level, message, emoji: true, io: $stderr)
14
- emoji_opt, shellcode = case level
15
- when :error
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
- # Escape the message for bash shell codes (e.g. \e[1;31m)
37
- escaped = message.gsub("\\", "\\\\\\").gsub("\e", "\\e")
24
+ def logger
25
+ return @logger if @logger
38
26
 
39
- io.puts "#{shellcode}#{emoji_opt}#{escaped}\e[0m"
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
- def default_docker_command
43
- return @default_docker_command if defined?(@default_docker_command)
31
+ OptionParser.new do |opts|
32
+ opts.banner = <<~MSG
33
+ Usage: rb-sys-dock [OPTIONS] [COMMAND]
44
34
 
45
- @default_docker_command = ENV.fetch("DOCKER", "docker")
46
- end
35
+ A CLI to facillitate building Ruby on Rust extensions using Docker.
47
36
 
48
- def run_command!(cmd)
49
- log(:trace, "Running command: $ #{cmd}")
50
- stdout, stderr, status = Open3.capture3(cmd)
37
+ Examples:
51
38
 
52
- if status.success?
53
- stdout
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
- def docker(cmd)
62
- require "open3"
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
- run_command!("#{default_docker_command} #{cmd}")
65
- rescue Errno::ENOENT
66
- log(:trace, "Could not find docker command, trying podman")
45
+ Enter a shell
46
+ $ rb-sys-dock --list-platforms
67
47
 
68
- begin
69
- stdout = run_command!("podman #{cmd}")
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
- OptionParser.new do |opts|
79
- opts.banner = "Usage: rb-sys-dock --platform PLATFORM [COMMAND]"
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
- log(:error, "Platform #{p} is not supported, please use one of:\n\n#{list}")
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
- options[:platform] = p
99
- options[:toolchain_info] = toolchain_info
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
- options[:verbose] = true
119
+ logger.level = :trace
120
+ OPTIONS[:verbose] = true
139
121
  end
140
122
 
141
- opts.on("--build", "Build the Docker image") do
142
- options[:build] = true
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
- log(:trace, "Mounting cargo registry dir: #{dir}")
202
+ logger.trace("Mounting cargo registry dir: #{dir}")
176
203
  FileUtils.mkdir_p(dir)
177
204
 
178
- "--mount type=bind,source=#{File.join(local_registry_dir, dir)},target=#{File.join("/usr/local/cargo", dir)},readonly=false"
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(options)
186
- dir = File.join(cache_dir, options.fetch(:toolchain_info).platform, "bundle")
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
- log(:trace, "Mounting bundle cache: #{dir}")
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(options)
258
+ def tmp_target_dir
195
259
  return @tmp_target_dir if defined?(@tmp_target_dir)
196
260
 
197
- dir = File.join(Dir.pwd, "tmp", "rb-sys-dock", options.fetch(:toolchain_info).platform, "target")
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 mount_target_dir(options)
203
- "-v #{tmp_target_dir(options)}:#{File.join(Dir.pwd, "target")}"
266
+ def working_directory
267
+ OPTIONS.fetch(:directory)
204
268
  end
205
269
 
206
- def mount_command_history(options)
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, options.fetch(:platform), "commandhistory")
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, options)
282
+ def default_command_to_run(input_args)
215
283
  input_cmd = input_args.empty? ? "true" : input_args.join(" ")
216
284
 
217
- if options[:build]
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
- log(:notice, "Running default build command:")
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 mount_tmp_dir(options)
246
- "--mount type=bind,source=#{Dir.mktmpdir},destination=#{Dir.pwd}/tmp/#{options.fetch(:toolchain_info).platform},readonly=false"
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 rcd(input_args, options)
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
- -v #{Dir.pwd}:#{Dir.pwd} \
260
- #{mount_tmp_dir(options)} \
261
- #{mount_target_dir(options)} \
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
- #{mount_bundle_cache(options)} \
264
- #{mount_command_history(options)} \
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(options).inspect} \
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
- -e LC_ALL=#{ENV.fetch("LC_ALL", "en_US.UTF-8")} \
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, options)}
370
+ #{default_command_to_run(input_args)}
286
371
  SH
287
372
 
288
- log(:trace, "Running command: $ #{cmd}")
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(options)
380
+ def download_image
294
381
  image = ENV.fetch("RCD_IMAGE")
295
382
 
296
- if docker("images -q #{image}").strip.empty? || options[:no_cache]
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
- log(:notice, "Downloading container #{image.inspect}, this might take awhile...")
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(options)
304
- return if options[:build]
390
+ def log_some_useful_info
391
+ return if OPTIONS[:build]
305
392
 
306
393
  if ARGV.empty?
307
- log(:notice, "Entering shell in Docker container #{ENV["RCD_IMAGE"].inspect}")
394
+ logger.info("Entering shell in Docker container #{ENV["RCD_IMAGE"].inspect}")
308
395
  else
309
- log(:notice, "Running command #{ARGV.inspect} in Docker container #{ENV["RCD_IMAGE"].inspect}")
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(options)
314
- ENV["RCD_IMAGE"] ||= "rbsys/#{options[:toolchain_info].platform}:#{options[:version]}"
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(options)
318
- download_image(options)
319
- log_some_useful_info(options)
320
- rcd(ARGV, options)
413
+ set_env
414
+ lint_rb_sys
415
+ download_image
416
+ log_some_useful_info
417
+ rcd(ARGV)
@@ -12,10 +12,13 @@ module RbSys
12
12
  # Initializes a new Cargo::Metadata instance.
13
13
  #
14
14
  # @param name [String] the name of the Cargo project
15
- def initialize(name)
15
+ def initialize(name, deps: false)
16
16
  raise ArgumentError, "name must be a String" unless name.is_a?(String)
17
17
 
18
18
  @name = name
19
+ @cargo_metadata = nil
20
+ @package_metadata = nil
21
+ @deps = deps
19
22
  end
20
23
 
21
24
  # Returns the path where the Cargo project's Cargo.toml is located.
@@ -88,6 +91,13 @@ module RbSys
88
91
  package_metadata.fetch("metadata")
89
92
  end
90
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"]
99
+ end
100
+
91
101
  private
92
102
 
93
103
  def package_metadata
@@ -103,7 +113,8 @@ module RbSys
103
113
 
104
114
  ::Gem.load_yaml
105
115
  cargo = ENV["CARGO"] || "cargo"
106
- args = ["metadata", "--no-deps", "--format-version", "1"]
116
+ args = ["metadata", "--format-version", "1"]
117
+ args << "--no-deps" unless @deps
107
118
  out, stderr, status = Open3.capture3(cargo, *args)
108
119
  raise "exited with non-zero status (#{status})" unless status.success?
109
120
  data = Gem::SafeYAML.safe_load(out)
@@ -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 gem"
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 = nil)
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
@@ -246,7 +246,6 @@ module RbSys
246
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
247
247
  \t$(Q) rustup toolchain install $(RB_SYS_DEFAULT_TOOLCHAIN) --profile $(RB_SYS_RUSTUP_PROFILE)
248
248
  \t$(Q) rustup default $(RB_SYS_DEFAULT_TOOLCHAIN)
249
- \t$(Q) rustup component add rustfmt
250
249
 
251
250
  $(RUSTLIB): $(CARGO)
252
251
  #{endif_stmt}
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RbSys
4
- VERSION = "0.9.64"
4
+ VERSION = "0.9.65"
5
5
  end
data.tar.gz.sig CHANGED
Binary file
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.64
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-07 00:00:00.000000000 Z
33
+ date: 2023-02-13 00:00:00.000000000 Z
34
34
  dependencies: []
35
35
  description:
36
36
  email:
@@ -57,6 +57,7 @@ files:
57
57
  - lib/rb_sys/mkmf/config.rb
58
58
  - lib/rb_sys/toolchain_info.rb
59
59
  - lib/rb_sys/toolchain_info/data.rb
60
+ - lib/rb_sys/util/logger.rb
60
61
  - lib/rb_sys/version.rb
61
62
  homepage: https://oxidize-rb.github.io/rb-sys/
62
63
  licenses:
@@ -79,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
80
  - !ruby/object:Gem::Version
80
81
  version: '0'
81
82
  requirements: []
82
- rubygems_version: 3.4.2
83
+ rubygems_version: 3.4.6
83
84
  signing_key:
84
85
  specification_version: 4
85
86
  summary: Helpers for compiling Rust extensions for ruby
metadata.gz.sig CHANGED
Binary file