Module: Plushie::Binary
- Defined in:
- lib/plushie/binary.rb
Overview
Resolves the path to the plushie renderer binary.
Resolution order (explicit config raises if file missing; implicit discovery silently tries the next option):
- PLUSHIE_BINARY_PATH environment variable (explicit)
- Plushie.configuration.binary_path (explicit)
- Custom extension build in _build/plushie/custom/target/ (implicit)
- Downloaded binary in _build/plushie/bin/ (implicit)
- Sibling plushie-rust checkout's target/release,debug/ (implicit)
- System PATH (implicit)
Class Method Summary collapse
-
.arch_name ⇒ Object
private
Map Ruby architecture to binary architecture name.
-
.binary_name ⇒ String
Platform-specific binary filename.
-
.custom_build_path ⇒ String?
Path to a custom extension build binary.
-
.download!(version: PLUSHIE_RUST_VERSION, dest: nil) ⇒ String
Download the precompiled binary for the current platform.
-
.download_wasm!(version: PLUSHIE_RUST_VERSION, force: false, dir: nil) ⇒ String
Download the WASM renderer tarball and extract it.
-
.downloaded_path ⇒ String?
Path to the downloaded precompiled binary.
-
.os_name ⇒ Object
private
Map Ruby platform to binary OS name.
-
.path ⇒ String?
Resolve the binary path, or return nil.
-
.path! ⇒ String
Resolve and return the binary path, or raise with helpful instructions.
-
.release_url(version) ⇒ String
GitHub release download URL.
-
.resolve ⇒ String?
Full resolution chain.
-
.sibling_target_path ⇒ String?
Path to a plushie-renderer binary built in a sibling plushie-rust checkout.
-
.wasm_path ⇒ String
Path to the WASM output directory.
-
.which(cmd) ⇒ Object
private
Search PATH for an executable.
Class Method Details
.arch_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Map Ruby architecture to binary architecture name.
154 155 156 157 158 159 160 |
# File 'lib/plushie/binary.rb', line 154 def arch_name case RbConfig::CONFIG["host_cpu"] when /x86_64|amd64/i then "x86_64" when /aarch64|arm64/i then "aarch64" else raise Error, "unsupported architecture: #{RbConfig::CONFIG["host_cpu"]}" end end |
.binary_name ⇒ String
Returns platform-specific binary filename.
212 213 214 215 216 |
# File 'lib/plushie/binary.rb', line 212 def binary_name name = "plushie-renderer-#{os_name}-#{arch_name}" name += ".exe" if Gem.win_platform? name end |
.custom_build_path ⇒ String?
Path to a custom extension build binary. Checks both release and debug profiles.
117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/plushie/binary.rb', line 117 def custom_build_path build_dir = File.join("_build", "plushie", "custom", "target") return nil unless File.directory?(build_dir) bin_name = Plushie.configuration.build_name ext = Gem.win_platform? ? ".exe" : "" %w[release debug].each do |profile| path = File.join(build_dir, profile, "#{bin_name}#{ext}") return path if File.exist?(path) end nil end |
.download!(version: PLUSHIE_RUST_VERSION, dest: nil) ⇒ String
Download the precompiled binary for the current platform. Verifies the SHA-256 checksum against a .sha256 sidecar file.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/plushie/binary.rb', line 168 def download!(version: PLUSHIE_RUST_VERSION, dest: nil) require "net/http" require "uri" require "fileutils" require "digest" url = release_url(version) checksum_url = "#{url}.sha256" if dest FileUtils.mkdir_p(File.dirname(dest)) else dir = File.join("_build", "plushie", "bin") FileUtils.mkdir_p(dir) dest = File.join(dir, binary_name) end warn "Downloading plushie #{version} for #{os_name}-#{arch_name}..." binary_data = fetch_url(url) checksum_data = fetch_url(checksum_url) # The .sha256 file contains "hexdigest filename\n" or just "hexdigest\n" expected_sha = checksum_data.strip.split(/\s+/).first actual_sha = Digest::SHA256.hexdigest(binary_data) unless actual_sha == expected_sha raise Error, "checksum mismatch for #{binary_name}: " \ "expected #{expected_sha}, got #{actual_sha}" end File.binwrite(dest, binary_data) File.chmod(0o755, dest) unless Gem.win_platform? warn "Saved to #{dest} (#{binary_data.bytesize} bytes, SHA-256 verified)" dest end |
.download_wasm!(version: PLUSHIE_RUST_VERSION, force: false, dir: nil) ⇒ String
Download the WASM renderer tarball and extract it.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/plushie/binary.rb', line 257 def download_wasm!(version: PLUSHIE_RUST_VERSION, force: false, dir: nil) require "net/http" require "uri" require "fileutils" require "digest" require "rubygems/package" require "zlib" require "stringio" dir ||= wasm_path js_path = File.join(dir, "plushie_renderer_wasm.js") wasm_file = File.join(dir, "plushie_renderer_wasm_bg.wasm") if !force && File.exist?(js_path) && File.exist?(wasm_file) warn "WASM files already exist in #{dir}. Use force: true to re-download." return dir end archive_name = "plushie-renderer-wasm.tar.gz" url = "https://github.com/plushie-ui/plushie-renderer/releases/download/v#{version}/#{archive_name}" checksum_url = "#{url}.sha256" warn "Downloading #{archive_name}..." archive_data = fetch_url(url) checksum_data = fetch_url(checksum_url) expected_sha = checksum_data.strip.split(/\s+/).first actual_sha = Digest::SHA256.hexdigest(archive_data) unless actual_sha == expected_sha raise Error, "checksum mismatch for #{archive_name}: " \ "expected #{expected_sha}, got #{actual_sha}" end FileUtils.mkdir_p(dir) # Extract tar.gz using Ruby built-ins io = StringIO.new(archive_data) Zlib::GzipReader.wrap(io) do |gz| Gem::Package::TarReader.new(gz) do |tar| tar.each do |entry| next unless entry.file? dest = File.join(dir, File.basename(entry.full_name)) File.binwrite(dest, entry.read) end end end warn "Installed WASM files to #{dir} (SHA-256 verified)" dir end |
.downloaded_path ⇒ String?
Path to the downloaded precompiled binary.
134 135 136 137 138 139 |
# File 'lib/plushie/binary.rb', line 134 def downloaded_path dir = File.join("_build", "plushie", "bin") name = binary_name path = File.join(dir, name) File.exist?(path) ? path : nil end |
.os_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Map Ruby platform to binary OS name.
143 144 145 146 147 148 149 150 |
# File 'lib/plushie/binary.rb', line 143 def os_name case RbConfig::CONFIG["host_os"] when /linux/i then "linux" when /darwin/i then "darwin" when /mswin|mingw|cygwin/i then "windows" else raise Error, "unsupported OS: #{RbConfig::CONFIG["host_os"]}" end end |
.path ⇒ String?
Resolve the binary path, or return nil.
48 49 50 |
# File 'lib/plushie/binary.rb', line 48 def path resolve end |
.path! ⇒ String
Resolve and return the binary path, or raise with helpful instructions.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/plushie/binary.rb', line 25 def path! path = resolve unless path raise Error, <<~MSG.chomp plushie binary not found. To download a precompiled binary: rake plushie:download To build from source: rake plushie:build To use an existing binary: export PLUSHIE_BINARY_PATH=/path/to/plushie MSG end raise Error, "plushie binary not executable: #{path}" unless File.executable?(path) path end |
.release_url(version) ⇒ String
Returns GitHub release download URL.
207 208 209 |
# File 'lib/plushie/binary.rb', line 207 def release_url(version) "https://github.com/plushie-ui/plushie-renderer/releases/download/v#{version}/#{binary_name}" end |
.resolve ⇒ String?
Full resolution chain.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/plushie/binary.rb', line 55 def resolve # 1. Explicit env var (raises if set but missing) if (env_path = ENV["PLUSHIE_BINARY_PATH"]) return env_path if File.exist?(env_path) raise Error, "PLUSHIE_BINARY_PATH set but file not found: #{env_path}" end # 2. Explicit config (raises if set but missing) if (config_path = Plushie.configuration.binary_path) return config_path if File.exist?(config_path) raise Error, "Plushie.configuration.binary_path set to #{config_path.inspect} but file not found" end # 3. Custom extension build custom = custom_build_path return custom if custom # 4. Downloaded binary downloaded = downloaded_path return downloaded if downloaded # 5. Sibling plushie-rust checkout (convenient during local SDK development) sibling = sibling_target_path return sibling if sibling # 6. System PATH which("plushie") end |
.sibling_target_path ⇒ String?
Path to a plushie-renderer binary built in a sibling plushie-rust checkout. This is purely a developer-convenience fallback: it lets the Ruby SDK find the renderer when both repos live next to each other without requiring PLUSHIE_BINARY_PATH on every invocation. Checks release first, then debug.
The lookup roots are, in order:
- $PLUSHIE_RUST_SOURCE_PATH (if set)
- ../plushie-rust (relative to Dir.pwd)
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/plushie/binary.rb', line 95 def sibling_target_path roots = [] if (env_root = ENV["PLUSHIE_RUST_SOURCE_PATH"]) && !env_root.empty? roots << env_root end roots << File.("../plushie-rust", Dir.pwd) ext = Gem.win_platform? ? ".exe" : "" roots.each do |root| next unless File.directory?(root) %w[release debug].each do |profile| path = File.join(root, "target", profile, "plushie-renderer#{ext}") return path if File.executable?(path) end end nil end |
.wasm_path ⇒ String
Returns path to the WASM output directory.
311 312 313 |
# File 'lib/plushie/binary.rb', line 311 def wasm_path File.join("_build", "plushie-renderer", "wasm") end |
.which(cmd) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Search PATH for an executable.
220 221 222 223 224 225 226 |
# File 'lib/plushie/binary.rb', line 220 def which(cmd) ENV["PATH"]&.split(File::PATH_SEPARATOR)&.each do |dir| path = File.join(dir, cmd) return path if File.executable?(path) end nil end |