Module: TebakoRuntime

Defined in:
lib/tebako-runtime.rb,
lib/tebako-runtime/memfs.rb,
lib/tebako-runtime/version.rb,
lib/tebako-runtime/pre/seven-zip.rb,
lib/tebako-runtime/adapters/mn2pdf.rb

Overview

Unpack mn2pdf.jar

Constant Summary collapse

PRE_REQUIRE_MAP =
{
  "excavate" => "tebako-runtime/pre/excavate",
  "seven_zip_ruby" => "tebako-runtime/pre/seven-zip"
}.freeze
POST_REQUIRE_MAP =
{
  "ffi" => "tebako-runtime/adapters/ffi",
  "fiddle" => "tebako-runtime/adapters/fiddle",
  "jing" => "tebako-runtime/adapters/jing",
  "mn2pdf" => "tebako-runtime/adapters/mn2pdf",
  "mnconvert" => "tebako-runtime/adapters/mnconvert",
  "net/http" => "tebako-runtime/adapters/net-http",
  "sassc" => "tebako-runtime/adapters/sassc",
  "sinatra" => "tebako-runtime/adapters/sinatra"
}.freeze
MEMFS_STAT_FN =

The v2 multi-mount world: an extractable path is one HELD by the TFS mounts (the env image at COMPILER_MEMFS, payloads at their declared points) — the compiled-in prefix can no longer express it. The runtime executable's own tebako_fs_stat is the discriminator: it answers only mounted content (0); host paths (and jail-denied ones) answer otherwise. Fiddle::Handle::DEFAULT addresses the process image WITHOUT this gem's own fiddle adapter (dlopen(nil) routes through it and chokes on the nil).

begin
  Fiddle::Function.new(Fiddle::Handle::DEFAULT["tebako_fs_stat"],
                       [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
rescue StandardError
  nil
end
MEMFS_STAT_BUF =

struct stat is at most 512 bytes on every supported platform (darwin-arm64 and linux x86_64 use 144).

"\0".b * 512
COMPILER_MEMFS =
RUBY_PLATFORM =~ /mswin|mingw/ ? "A:/__tebako_memfs__" : "/__tebako_memfs__"
COMPILER_MEMFS_LIB_CACHE =
initialize_compiler_memfs_lib_cache
VERSION =
"0.8.0"
MN2PDF_J_PATH =
TebakoRuntime.extract_memfs(File.join(TebakoRuntime.full_gem_path("mn2pdf"), "bin",
"mn2pdf.jar"))

Class Method Summary collapse

Class Method Details

.embedded_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


58
59
60
61
62
# File 'lib/tebako-runtime/memfs.rb', line 58

def self.embedded_path?(path)
  return path.start_with?(COMPILER_MEMFS) if MEMFS_STAT_FN.nil?

  MEMFS_STAT_FN.call(path, MEMFS_STAT_BUF).zero? || path.start_with?(COMPILER_MEMFS)
end

.extract(file, wild, extract_path) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/tebako-runtime/memfs.rb', line 80

def self.extract(file, wild, extract_path)
  files = if wild
            Dir.glob("#{File.dirname(file)}/*#{File.extname(file)}")
          else
            [file]
          end
  FileUtils.cp_r files, extract_path
end

.extract_memfs(file, wild: false, cache_path: COMPILER_MEMFS_LIB_CACHE) ⇒ Object

wild == true means "also extract other files with the same extension"



90
91
92
93
94
95
96
97
98
99
# File 'lib/tebako-runtime/memfs.rb', line 90

def self.extract_memfs(file, wild: false, cache_path: COMPILER_MEMFS_LIB_CACHE)
  is_quoted = file.quoted?
  file = file.unquote if is_quoted
  return is_quoted ? file.quote : file unless File.exist?(file) && embedded_path?(file)

  memfs_extracted_file = cache_path + File.basename(file)
  extract(file, wild, cache_path) unless memfs_extracted_file.exist?

  is_quoted ? memfs_extracted_file.to_path.quote : memfs_extracted_file.to_path
end

.full_gem_path(gem) ⇒ Object



55
56
57
# File 'lib/tebako-runtime.rb', line 55

def self.full_gem_path(gem)
  Gem::Specification.find_by_name(gem).full_gem_path
end

.initialize_compiler_memfs_lib_cacheObject



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/tebako-runtime/memfs.rb', line 64

def self.initialize_compiler_memfs_lib_cache
  Pathname.new(Dir.mktmpdir("tebako-runtime-"))
rescue StandardError
  return nil unless defined?($tebako_original_pwd) && !$tebako_original_pwd.nil? # rubocop:disable Style/GlobalVars

  begin
    Pathname.new(Dir.mktmpdir("tebako-runtime-", $tebako_original_pwd)) # rubocop:disable Style/GlobalVars
  rescue StandardError
    nil
  end
end

.log_enabledObject



59
60
61
# File 'lib/tebako-runtime.rb', line 59

def self.log_enabled
  @log_enabled ||= false
end

.process(name, map, title) ⇒ Object



63
64
65
66
67
68
69
70
# File 'lib/tebako-runtime.rb', line 63

def self.process(name, map, title)
  return !log_enabled unless map.key?(name)

  puts "Tebako runtime: req/#{title} [#{name} => #{map[name]}]" if log_enabled
  res_inner = require_relative map[name]
  puts "Tebako runtime: skipped [#{name}]" if log_enabled && !res_inner
  log_enabled
end

.process_all(name) ⇒ Object



72
73
74
75
76
77
78
79
# File 'lib/tebako-runtime.rb', line 72

def self.process_all(name)
  f1 = process(name, PRE_REQUIRE_MAP, "pre")
  res = original_require name
  f2 = process(name, POST_REQUIRE_MAP, "post")

  puts "Tebako runtime: req [#{name}]" unless f1 || f2
  res
end

.process_pass_through(name) ⇒ Object

Very special deploy-time patching It targets ffi-compiler/ffi-compiler2 that use some functions of deployed ffi to process other gems This approach is not compatible with tebako on Windows because ffi is deployed with (implib) reference to target tebako package that is not available at deploy time



87
88
89
90
91
92
93
94
95
# File 'lib/tebako-runtime.rb', line 87

def self.process_pass_through(name)
  if name == "ffi" && RUBY_PLATFORM =~ /mswin|mingw/
    puts "Replacing ffi ffi-platform-stub" if log_enabled
    res = original_require "tebako-runtime/pass-through/ffi-platform-stub"
  else
    res = original_require name
  end
  res
end

.set_bundle_gemfileObject



97
98
99
100
101
102
# File 'lib/tebako-runtime.rb', line 97

def self.set_bundle_gemfile
  return if ENV["TEBAKO_PASS_THROUGH"]

  bundle_gemfile = File.join(COMPILER_MEMFS, ".bundle", "Gemfile")
  ENV["BUNDLE_GEMFILE"] = bundle_gemfile if File.exist?(bundle_gemfile)
end