Class: Ocran::ZipPayloadBuilder
- Inherits:
-
Object
- Object
- Ocran::ZipPayloadBuilder
- Includes:
- BuildConstants
- Defined in:
- lib/ocran/zip_payload_builder.rb
Overview
Builder that packages an application by INJECTING it into the ZIP store of a cosmopolitan Ruby APE, instead of building a launcher stub that unpacks a temporary directory at every start.
A CosmoRuby build auto-runs the member /zip/main.rb of its own archive when there is one, passing the command line through as ARGV. So a complete application is: a byte-for-byte copy of ruby.com, plus the application's files, plus a generated main.rb that prepares the environment and loads the real script. Nothing is compiled at packaging time (no cosmocc) and nothing is written to disk at run time (no extraction, no temp directory).
Layout inside the archive:
/zip/main.rb generated bootstrap, the entry point
/zip/ocran/src/... the application's own files
/zip/ocran/gems/... packed pure-Ruby gems (GEM_HOME/GEM_PATH)
/zip/ocran/lib/ruby/... files packed relative to the Ruby prefix
Everything except main.rb lives under the "ocran/" prefix because the interpreter's own standard library already occupies /zip/lib/ruby and /zip/bin: a shared namespace would let a packed file shadow part of the interpreter. The prefix makes collisions structurally impossible, and it is the same tree the extraction mode would have written to a temp directory, so Direction needs no separate layout.
Constant Summary collapse
- ZIP_ROOT =
Where the interpreter maps its embedded archive.
"/zip"- APP_ROOT =
Root of the packed application inside the archive.
"#{ZIP_ROOT}/ocran"- MAIN_SCRIPT =
Archive member the interpreter runs on startup.
"main.rb"
Constants included from BuildConstants
BuildConstants::BINDIR, BuildConstants::EXTRACT_ROOT, BuildConstants::GEMDIR, BuildConstants::LIBDIR, BuildConstants::SRCDIR
Instance Attribute Summary collapse
-
#data_size ⇒ Object
readonly
Uncompressed size of everything packed, for the build summary.
-
#ignored_symlinks ⇒ Object
readonly
Symlinks the extraction mode would create (libruby aliases).
Class Method Summary collapse
-
.parse_rubyopt(rubyopt) ⇒ Object
Splits a RUBYOPT string into the -I directories and -r libraries that can be replayed from inside the script, and the flags that cannot.
Instance Method Summary collapse
- #cp(source, target) ⇒ Object
-
#exec(image, script, *argv) ⇒ Object
The image argument is the packed interpreter the extraction mode would spawn; here the running interpreter IS that binary, so only the script and its arguments matter.
- #export(name, value) ⇒ Object
-
#initialize(path, cosmo_ruby:, chdir_before: false, debug_mode: false) {|_self| ... } ⇒ ZipPayloadBuilder
constructor
A new instance of ZipPayloadBuilder.
- #mkdir(target) ⇒ Object
- #symlink(link_path, target) ⇒ Object
Constructor Details
#initialize(path, cosmo_ruby:, chdir_before: false, debug_mode: false) {|_self| ... } ⇒ ZipPayloadBuilder
Returns a new instance of ZipPayloadBuilder.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/ocran/zip_payload_builder.rb', line 46 def initialize(path, cosmo_ruby:, chdir_before: false, debug_mode: false) @path = Pathname(path) @cosmo_ruby = Pathname(cosmo_ruby) @chdir_before = chdir_before @debug_mode = debug_mode @entries = [] @names = {} @env = {} @exec_args = nil @ignored_symlinks = [] @data_size = 0 yield(self) if block_given? finalize end |
Instance Attribute Details
#data_size ⇒ Object (readonly)
Uncompressed size of everything packed, for the build summary.
44 45 46 |
# File 'lib/ocran/zip_payload_builder.rb', line 44 def data_size @data_size end |
#ignored_symlinks ⇒ Object (readonly)
Symlinks the extraction mode would create (libruby aliases). A ZIP member cannot be a symlink zipos would follow, and none are needed: the packed interpreter is a single static binary.
66 67 68 |
# File 'lib/ocran/zip_payload_builder.rb', line 66 def ignored_symlinks @ignored_symlinks end |
Class Method Details
.parse_rubyopt(rubyopt) ⇒ Object
Splits a RUBYOPT string into the -I directories and -r libraries that can be replayed from inside the script, and the flags that cannot. Returns [includes, requires, unsupported].
268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/ocran/zip_payload_builder.rb', line 268 def self.parse_rubyopt(rubyopt) includes, requires, unsupported = [], [], [] rubyopt.split(/\s+/).reject(&:empty?).each do |token| case token when /\A-I(.+)\z/ then includes << $1 when /\A-r(.+)\z/ then requires << $1 else unsupported << token end end [includes, requires, unsupported] end |
Instance Method Details
#cp(source, target) ⇒ Object
72 73 74 75 76 77 |
# File 'lib/ocran/zip_payload_builder.rb', line 72 def cp(source, target) source = source.to_s add(Entry.new(name: archive_name(target), source: source, mode: file_mode(source), mtime: File.mtime(source))) @data_size += File.size(source) end |
#exec(image, script, *argv) ⇒ Object
The image argument is the packed interpreter the extraction mode would spawn; here the running interpreter IS that binary, so only the script and its arguments matter.
90 91 92 93 |
# File 'lib/ocran/zip_payload_builder.rb', line 90 def exec(image, script, *argv) raise "Script is already set" if @exec_args @exec_args = [in_archive(image), in_archive(script), argv.map { |arg| replace_root(arg.to_s) }] end |
#export(name, value) ⇒ Object
83 84 85 |
# File 'lib/ocran/zip_payload_builder.rb', line 83 def export(name, value) @env[name.to_s] = replace_root(value.to_s) end |
#mkdir(target) ⇒ Object
68 69 70 |
# File 'lib/ocran/zip_payload_builder.rb', line 68 def mkdir(target) add(Entry.new(name: "#{archive_name(target)}/")) end |
#symlink(link_path, target) ⇒ Object
79 80 81 |
# File 'lib/ocran/zip_payload_builder.rb', line 79 def symlink(link_path, target) @ignored_symlinks << [link_path.to_s, target.to_s] end |