Module: Ruflet::Rails::WebInstaller
- Defined in:
- lib/ruflet/rails/web_installer.rb
Overview
Installs the prebuilt Ruflet web client into a Rails app's frontend/
directory. The web client is the ruflet_client-web.tar.gz release asset
(the same prebuilt Flutter web build shipped on GitHub releases) — so the
Rails app serves a web frontend without ever running a Flutter build.
rake ruflet:web
The extracted build is what Ruflet::Rails.web_app serves (its default build dir is <Rails.root>/frontend).
Constant Summary collapse
- REPO =
"AdamMusa/Ruflet"- ASSET_NAME =
"ruflet_client-web.tar.gz"- TARGET_DIR =
"frontend"
Class Method Summary collapse
- .download(url, path) ⇒ Object
- .env_asset_name ⇒ Object
- .env_tag ⇒ Object
- .extract(archive, target) ⇒ Object
- .github_json(url) ⇒ Object
-
.install!(root:, dir: TARGET_DIR, asset_name: env_asset_name, tag: env_tag, force: true) ⇒ Object
Downloads and extracts the web client into
/ . - .release_asset_url(asset_name, tag: nil) ⇒ Object
- .replace_target(staging, target) ⇒ Object
- .safe_archive?(archive) ⇒ Boolean
Class Method Details
.download(url, path) ⇒ Object
93 94 95 96 97 |
# File 'lib/ruflet/rails/web_installer.rb', line 93 def download(url, path) ok = system("curl", "-sSL", "--fail", "-o", path, url) warn "Download failed: #{url}" unless ok ok end |
.env_asset_name ⇒ Object
126 127 128 129 |
# File 'lib/ruflet/rails/web_installer.rb', line 126 def env_asset_name value = ENV["RUFLET_RAILS_WEB_ARTIFACT"].to_s.strip value.empty? ? ASSET_NAME : value end |
.env_tag ⇒ Object
131 132 133 134 |
# File 'lib/ruflet/rails/web_installer.rb', line 131 def env_tag value = ENV["RUFLET_RAILS_WEB_TAG"].to_s.strip value.empty? ? nil : value end |
.extract(archive, target) ⇒ Object
99 100 101 |
# File 'lib/ruflet/rails/web_installer.rb', line 99 def extract(archive, target) system("tar", "-xzf", archive, "-C", target) end |
.github_json(url) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/ruflet/rails/web_installer.rb', line 79 def github_json(url) out, status = Open3.capture2( "curl", "-sSL", "--fail", "-H", "Accept: application/vnd.github+json", "-H", "User-Agent: ruflet_rails", url ) return nil unless status.success? JSON.parse(out) rescue JSON::ParserError nil end |
.install!(root:, dir: TARGET_DIR, asset_name: env_asset_name, tag: env_tag, force: true) ⇒ Object
Downloads and extracts the web client into
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/ruflet/rails/web_installer.rb', line 29 def install!(root:, dir: TARGET_DIR, asset_name: env_asset_name, tag: env_tag, force: true) target = File.join(root.to_s, dir) url = release_asset_url(asset_name, tag: tag) unless url warn "Ruflet web client asset #{asset_name.inspect} not found in the #{REPO} release#{tag ? " #{tag}" : " (latest)"}." return false end Dir.mktmpdir("ruflet-web-") do |tmp| archive = File.join(tmp, asset_name) return false unless download(url, archive) staging = File.join(tmp, "frontend") FileUtils.mkdir_p(staging) unless safe_archive?(archive) && extract(archive, staging) warn "Failed to safely extract #{asset_name}." return false end unless File.file?(File.join(staging, "index.html")) warn "Extracted web client but no index.html was found." return false end return false if Dir.exist?(target) && !force replace_target(staging, target) end puts "Installed Ruflet web client into #{target} (#{asset_name})." true rescue SystemCallError => e warn "Failed to install Ruflet web client into #{target}: #{e.}" false end |
.release_asset_url(asset_name, tag: nil) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/ruflet/rails/web_installer.rb', line 66 def release_asset_url(asset_name, tag: nil) api = tag ? "releases/tags/#{tag}" : "releases/latest" release = github_json("https://api.github.com/repos/#{REPO}/#{api}") return nil unless release asset = Array(release["assets"]).find { |a| a["name"] == asset_name } unless asset names = Array(release["assets"]).map { |a| a["name"] } warn "Available release assets: #{names.join(', ')}" unless names.empty? end asset && asset["browser_download_url"] end |
.replace_target(staging, target) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/ruflet/rails/web_installer.rb', line 113 def replace_target(staging, target) FileUtils.mkdir_p(File.dirname(target)) backup = "#{target}.ruflet-backup" FileUtils.rm_rf(backup) FileUtils.mv(target, backup) if File.exist?(target) FileUtils.mv(staging, target) FileUtils.rm_rf(backup) rescue StandardError FileUtils.rm_rf(target) FileUtils.mv(backup, target) if File.exist?(backup) raise end |
.safe_archive?(archive) ⇒ Boolean
103 104 105 106 107 108 109 110 111 |
# File 'lib/ruflet/rails/web_installer.rb', line 103 def safe_archive?(archive) out, status = Open3.capture2("tar", "-tzf", archive) return false unless status.success? out.lines.all? do |line| path = line.strip !path.start_with?("/") && path.split("/").none?("..") end end |