Class: Tebako::RuntimeManager
- Inherits:
-
Object
- Object
- Tebako::RuntimeManager
- Defined in:
- lib/tebako/runtime_manager.rb
Overview
Resolution, download, verification and machine-wide caching of prebuilt tebako runtime packages published by tamatebako/tebako-runtime-ruby.
Cache layout (rooted at $TEBAKO_HOME or ~/.tebako):
runtimes/ruby-<ruby-version>-<tebakoabi>-<platform>/
tebako-runtime-<tebakoabi>-<ruby-version>-<platform>[.exe]
sha256 -- digest the installed file was verified against
origin -- URL the package was downloaded from
Installs are serialized per entry with a flock'd lockfile; packages are downloaded to tmp/, SHA256-verified against the release index and moved into place with an atomic rename, so partial downloads never poison the cache.
Direct Known Subclasses
Defined Under Namespace
Classes: DownloadFailed, IndexUnavailable
Constant Summary collapse
- DEFAULT_MIRROR =
rubocop:disable Metrics/ClassLength
"https://github.com/tamatebako/tebako-runtime-ruby/releases/download"- RUNTIMES_DIR =
"runtimes"- TMP_DIR =
"tmp"- LOCK_FILE =
".install.lock"- SHA256_FILE =
"sha256"- ORIGIN_FILE =
"origin"- RUNTIME_TYPE =
"ruby"- LOCK_TIMEOUT =
300- DOWNLOAD_ATTEMPTS =
3- RETRY_DELAY =
1.0- REDIRECT_LIMIT =
5- INDEX_FILES =
["manifest.json", "SHA256SUMS.txt"].freeze
Instance Attribute Summary collapse
-
#cache_root ⇒ Object
readonly
Returns the value of attribute cache_root.
Class Method Summary collapse
- .default_cache_root ⇒ Object
- .layout(runtime_path) ⇒ Object
- .resolve(ruby_version, platform, tebako_version: Tebako::VERSION) ⇒ Object
Instance Method Summary collapse
- #entries ⇒ Object
-
#initialize(cache_root: nil, mirror: nil, lock_timeout: LOCK_TIMEOUT, retry_delay: RETRY_DELAY) ⇒ RuntimeManager
constructor
A new instance of RuntimeManager.
-
#layout(runtime_path) ⇒ Object
Extract the runtime package's filesystem layout next to the cached package (idempotent) and return the layout root.
- #prune(all: false, older_than_days: nil) ⇒ Object
- #resolve(ruby_version, platform, tebako_version: Tebako::VERSION) ⇒ Object
Constructor Details
#initialize(cache_root: nil, mirror: nil, lock_timeout: LOCK_TIMEOUT, retry_delay: RETRY_DELAY) ⇒ RuntimeManager
Returns a new instance of RuntimeManager.
93 94 95 96 97 98 |
# File 'lib/tebako/runtime_manager.rb', line 93 def initialize(cache_root: nil, mirror: nil, lock_timeout: LOCK_TIMEOUT, retry_delay: RETRY_DELAY) @cache_root = cache_root || self.class.default_cache_root @mirror = (mirror || ENV.fetch(mirror_env_var, nil) || default_mirror).sub(%r{/+\z}, "") @lock_timeout = lock_timeout @retry_delay = retry_delay end |
Instance Attribute Details
#cache_root ⇒ Object (readonly)
Returns the value of attribute cache_root.
100 101 102 |
# File 'lib/tebako/runtime_manager.rb', line 100 def cache_root @cache_root end |
Class Method Details
.default_cache_root ⇒ Object
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/tebako/runtime_manager.rb', line 73 def default_cache_root tebako_home = ENV.fetch("TEBAKO_HOME", nil) return tebako_home unless tebako_home.nil? || tebako_home.empty? if Gem.win_platform? File.join(ENV.fetch("LOCALAPPDATA", File.join(Dir.home, "AppData", "Local")), "tebako") else File.join(Dir.home, ".tebako") end end |
.layout(runtime_path) ⇒ Object
88 89 90 |
# File 'lib/tebako/runtime_manager.rb', line 88 def layout(runtime_path) new.layout(runtime_path) end |
Instance Method Details
#entries ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/tebako/runtime_manager.rb', line 129 def entries base = File.join(@cache_root, cache_subdir) return [] unless Dir.exist?(base) Dir.children(base).sort.filter_map do |name| path = File.join(base, name) next unless File.directory?(path) { name: name, path: path, size_bytes: dir_size(path), installed_at: File.mtime(path) } end end |
#layout(runtime_path) ⇒ Object
Extract the runtime package's filesystem layout next to the cached package (idempotent) and return the layout root. The layout is the authoritative source of the runtime's arch conventions (rbconfig location, gem extension dir naming), which the application image must match: ruby's compiled-in search paths come from the runtime build, while a local packaging environment names them after the press machine (macOS embeds the kernel version, e.g. arm64-darwin23 vs -darwin24).
120 121 122 123 124 125 126 127 |
# File 'lib/tebako/runtime_manager.rb', line 120 def layout(runtime_path) layout_dir = File.join(File.dirname(runtime_path), "layout") return layout_dir if File.directory?(File.join(layout_dir, "lib")) FileUtils.mkdir_p(layout_dir) Tebako::BuildHelpers.run_with_capture_v([runtime_path, "--tebako-extract", layout_dir]) layout_dir end |
#prune(all: false, older_than_days: nil) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/tebako/runtime_manager.rb', line 141 def prune(all: false, older_than_days: nil) raise ArgumentError, "prune requires :all or :older_than_days" unless all || older_than_days cutoff = older_than_days && (Time.now - (older_than_days * 86_400)) entries.each_with_object([]) do |entry, removed| next unless all || entry[:installed_at] < cutoff FileUtils.rm_rf(entry[:path], secure: true) removed << entry[:name] end end |
#resolve(ruby_version, platform, tebako_version: Tebako::VERSION) ⇒ Object
102 103 104 105 106 107 108 109 110 111 |
# File 'lib/tebako/runtime_manager.rb', line 102 def resolve(ruby_version, platform, tebako_version: Tebako::VERSION) dir = entry_dir(ruby_version, platform, tebako_version) executable = File.join(dir, runtime_filename(ruby_version, platform, tebako_version)) return executable if File.file?(executable) with_entry_lock(dir, runtime_ref(ruby_version, platform, tebako_version)) do install(executable, ruby_version, platform, tebako_version) unless File.file?(executable) end executable end |