Module: Tebako::SingleFileBundle

Defined in:
lib/tebako/single_file_bundle.rb

Overview

Atomically combines a layered application with a reusable runtime executable.

Defined Under Namespace

Classes: Inspection

Constant Summary collapse

Format =
Tebako::Generated::SingleFileBundleFormat
MACHO_64_MAGIC =
"\xcf\xfa\xed\xfe".b
MACHO_SEGMENT_64 =
0x19
MACHO_HEADER_SIZE =
32
MACHO_SEGMENT_SIZE =
72
MACHO_SECTION_SIZE =
80
MACHO_SEGMENT =
"__TEBAKO"
MACHO_SECTION =
"__app"

Class Method Summary collapse

Class Method Details

.application_bytes(path) ⇒ Object



102
103
104
105
106
107
# File 'lib/tebako/single_file_bundle.rb', line 102

def application_bytes(path)
  data = File.binread(path)
  envelope, = locate_envelope(data)
  application, = decode(envelope, require_runtime: false)
  application
end

.bundle?(path) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
# File 'lib/tebako/single_file_bundle.rb', line 47

def bundle?(path)
  return false unless File.file?(path)

  data = File.binread(path)
  appended_bundle?(data) || !macho_envelope(data).nil?
rescue SystemCallError
  false
end

.inspect(path) ⇒ Object

Raises:

  • (ArgumentError)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/tebako/single_file_bundle.rb', line 82

def inspect(path)
  data = File.binread(path)
  envelope, runtime_size, container = locate_envelope(data)
  application, _, digest = decode(envelope, require_runtime: false)
  actual_digest = Digest::SHA256.hexdigest(application)
  raise ArgumentError, "Single-file bundle application checksum is invalid" unless actual_digest == digest

  Inspection.new(
    format: "single_file_bundle",
    container: container,
    major_version: Format::MAJOR_VERSION,
    minor_version: Format::MINOR_VERSION,
    runtime_size: runtime_size,
    application_size: application.bytesize,
    application_sha256: digest,
    byte_size: data.bytesize,
    application: Tebako::LayeredPackage.inspect_bytes(application)
  )
end

.write(output, runtime:, application:, assembler: nil) ⇒ Object



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
# File 'lib/tebako/single_file_bundle.rb', line 56

def write(output, runtime:, application:, assembler: nil)
  application_inspection = Tebako::LayeredPackage.inspect(application)
  temporary = "#{output}.#{Process.pid}.#{SecureRandom.hex(6)}.tmp"
  payload = "#{temporary}.payload"
  FileUtils.mkdir_p(File.dirname(File.expand_path(output)))
  write_envelope(payload, application, application_inspection.sha256)
  if assembler
    assembler.call(temporary, payload)
  else
    File.open(temporary, "wb") do |bundle|
      File.open(runtime, "rb") { |source| IO.copy_stream(source, bundle) }
      File.open(payload, "rb") { |source| IO.copy_stream(source, bundle) }
      bundle.flush
      bundle.fsync
    end
  end
  FileUtils.chmod(File.stat(runtime).mode & 0o7777, temporary)
  inspection = inspect(temporary)
  File.rename(temporary, output)
  report(runtime, application, output, inspection.container)
  output
ensure
  FileUtils.rm_f(temporary) if temporary
  FileUtils.rm_f(payload) if payload
end