tebako 0.15.2 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40cccec56036f14133e05046f858915c7f6ae657c11f3560b647d791c2cc952a
4
- data.tar.gz: 79022b3acb1d0457a996f671ca93e69ac024107156f31445f27159a1d81ac7da
3
+ metadata.gz: 8ec3da7722b76d52f17d341664974ff8ea5f5164feec924958cd2725238439d0
4
+ data.tar.gz: 2e244d8b29c27a4f884aa969961dca6968323d21376012bf539dbce28c5b7baa
5
5
  SHA512:
6
- metadata.gz: 318cab0bce4b6528efe1e1c215b473344311f68fcef2bc7ac379cdc81248c06afac942fff0b55a9dd5e45b88f5989031597ef633c4e6e6d69ed2478a83138b13
7
- data.tar.gz: 0f3b13569b1ffd26de43d6233bfb2579fe91e1d6107b51370562c64e2f0f87021813bb1129eaafaae9f68202e0c37d9d03cf9d439ce5610ff857493278fe6838
6
+ metadata.gz: ccf67b3e4bf6444ca31627b27e9876699f743cdac01e2ebea0cee29a9ea8113d24d5ef34d6b15ebd8461620c8e29bb3d75ef7332b5a1934e3b3d579130cdb871
7
+ data.tar.gz: 51695b16c05b1063678bc2f4c6042ae65c3111799f14f81a5d3982a30c4f94f74f7f28d2fa587c11cdcf509ff9a5f105428ed95eff693d47377337980d349177
data/CMakeLists.txt CHANGED
@@ -217,6 +217,7 @@ endif()
217
217
  def_ext_prj_g(PATCHELF "65e14792061c298f1d2bc44becd48a10cbf0bc81")
218
218
 
219
219
  set(LIBYAML_RUBY_OPTION "")
220
+ set(RUBY_LIBS "")
220
221
  if(${RUBY_VER} VERSION_LESS "3.2.0")
221
222
  set(LIBYAML_RUBY_OPTION "--enable-bundled-libyaml")
222
223
  endif(${RUBY_VER} VERSION_LESS "3.2.0")
@@ -397,6 +398,16 @@ else(IS_DARWIN)
397
398
  if(RB_W32)
398
399
  string(CONCAT RUBY_C_FLAGS ${RUBY_C_FLAGS} " -DRB_W32=1")
399
400
  string(CONCAT RUBY_L_FLAGS ${RUBY_L_FLAGS} " -l:libstdc++.a -L${TLIBD}")
401
+ # vcpkg's static libcrypto.a (the CAPI engine, e_capi.obj) references
402
+ # the CryptoAPI certificate store (CertFreeCertificateContext & co.),
403
+ # but ruby's default mingw $LIBS lack -lcrypt32, so every ext/openssl
404
+ # have_func link probe failed with undefined Cert* references and the
405
+ # OpenSSL-1.1.0 accessor fallbacks in openssl_missing.c compiled
406
+ # against opaque 3.x structs (tebako#345). mkmf appends $LIBS after
407
+ # -lssl/-lcrypto, so LIBS here lands in the right order for static
408
+ # linking; advapi32/user32 cover the rest of the usual static-openssl
409
+ # system-lib tail.
410
+ set(RUBY_LIBS "-lcrypt32 -ladvapi32 -luser32")
400
411
  set(C_FLAGS_DEST cppflags)
401
412
  endif(RB_W32)
402
413
 
@@ -432,7 +443,8 @@ ExternalProject_Add(${RUBY_PRJ}
432
443
  --with-out-ext=${RUBY_WITHOUT_EXT} \
433
444
  --prefix=${DATA_SRC_DIR} \
434
445
  ${C_FLAGS_DEST}=\"${RUBY_C_FLAGS}\" \
435
- LDFLAGS=\"${RUBY_L_FLAGS}\""
446
+ LDFLAGS=\"${RUBY_L_FLAGS}\" \
447
+ LIBS=\"${RUBY_LIBS}\""
436
448
  COMMAND ruby ${EXE}/tebako-packager pass2 ${OSTYPE_TXT} ${RUBY_SOURCE_DIR} ${DEPS_LIB_DIR} ${DATA_SRC_DIR} ${RUBY_STASH_DIR} ${RUBY_VER}
437
449
  INSTALL_COMMAND ""
438
450
  )
@@ -50,7 +50,7 @@
50
50
  * 8 8 u64 size (image length in bytes)
51
51
  * 16 4 u32 format_id (0=auto(magic), 1=dwarfs, 2=squashfs, 3=zip, 4=runtime payload)
52
52
  * 20 4 u32 flags
53
- * 24 256 char mount_point[256] (UTF-8, NUL-padded; empty for runtime payloads)
53
+ * 24 256 char mount_point[256] (UTF-8, NUL-padded)
54
54
  *
55
55
  * Reader algorithm: read the fixed-size header at EOF - TPKG_HEADER_SIZE,
56
56
  * check the magic, verify header_crc32, then read slot_count slot records at
@@ -97,8 +97,8 @@ extern "C" {
97
97
  #define TPKG_MOUNT_POINT_LEN 256u
98
98
  #define TPKG_RUNTIME_REF_LEN 128u
99
99
  #define TPKG_MAGIC "TEBAKOTFS"
100
- #define TPKG_MAGIC_LEN 10u /* including the terminating NUL */
101
- #define TPKG_MAGIC_PREFIX_LEN 4u /* "TEBA": absent-vs-corrupt discriminator */
100
+ #define TPKG_MAGIC_LEN 10u /* including the terminating NUL */
101
+ #define TPKG_MAGIC_PREFIX_LEN 4u /* "TEBA": absent-vs-corrupt discriminator */
102
102
 
103
103
  /* package_flags */
104
104
  #define TPKG_FLAG_LEAN 0x1u
@@ -108,8 +108,8 @@ extern "C" {
108
108
  #define TPKG_FORMAT_DWARFS 1u
109
109
  #define TPKG_FORMAT_SQUASHFS 2u
110
110
  #define TPKG_FORMAT_ZIP 3u
111
- /* runtime payload slot of a fat package: the bootstrap installs it into the
112
- * shared cache at first run; it is never mounted as a filesystem image */
111
+ /* A runtime payload slot (fat packages): the compressed language-runtime
112
+ * package the bootstrap installs into the shared cache on first run. */
113
113
  #define TPKG_FORMAT_RUNTIME 4u
114
114
 
115
115
  /* ---- error codes (returned by tpkg_errno) -------------------------------- */
@@ -223,19 +223,12 @@ enum {
223
223
  };
224
224
 
225
225
  /* slot record field offsets */
226
- enum {
227
- TPKG__REC_OFFSET = 0,
228
- TPKG__REC_SIZE = 8,
229
- TPKG__REC_FORMAT = 16,
230
- TPKG__REC_FLAGS = 20,
231
- TPKG__REC_MOUNT = 24
232
- };
226
+ enum { TPKG__REC_OFFSET = 0, TPKG__REC_SIZE = 8, TPKG__REC_FORMAT = 16, TPKG__REC_FLAGS = 20, TPKG__REC_MOUNT = 24 };
233
227
 
234
228
  /* wire sizes are fixed by the format; catch exotic padding at compile time */
235
229
  typedef char tpkg__assert_slot_size[(sizeof(tpkg_slot) == TPKG_SLOT_SIZE) ? 1 : -1];
236
- typedef char tpkg__assert_manifest_size[(sizeof(tpkg_manifest) ==
237
- 4 * sizeof(uint32_t) + TPKG_RUNTIME_REF_LEN +
238
- TPKG_MAX_SLOTS * sizeof(tpkg_slot))
230
+ typedef char tpkg__assert_manifest_size[(sizeof(tpkg_manifest) == 4 * sizeof(uint32_t) + TPKG_RUNTIME_REF_LEN +
231
+ TPKG_MAX_SLOTS * sizeof(tpkg_slot))
239
232
  ? 1
240
233
  : -1];
241
234
 
@@ -112,7 +112,8 @@ module Tebako
112
112
  def do_press_prebuilt(options_manager, scenario_manager)
113
113
  Tebako::Packager.check_prebuilt_env!(options_manager.stash_dir, options_manager.deps_bin_dir)
114
114
  runtime_path = Tebako::RuntimeManager.resolve(options_manager.ruby_ver, options_manager.host_platform)
115
- app_image = Tebako::Packager.build_app_image(options_manager, scenario_manager)
115
+ app_image = Tebako::Packager.build_app_image(options_manager, scenario_manager,
116
+ Tebako::RuntimeManager.layout(runtime_path))
116
117
 
117
118
  images = [{ path: app_image, mount_point: scenario_manager.fs_mount_point,
118
119
  format_id: Tebako::Stitcher::FORMAT_DWARFS }] + options_manager.images
@@ -128,33 +129,39 @@ module Tebako
128
129
  # slot, so the first run installs it without any network access.
129
130
  def do_press_three_part(options_manager, scenario_manager)
130
131
  bootstrap_path, runtime_path = resolve_three_part_parts(options_manager)
131
- app_image = Tebako::Packager.build_app_image(options_manager, scenario_manager)
132
- images = three_part_images(options_manager, scenario_manager, app_image, runtime_path)
132
+ app_image = Tebako::Packager.build_app_image(options_manager, scenario_manager,
133
+ Tebako::RuntimeManager.layout(runtime_path))
134
+ payload_path = options_manager.fat? ? runtime_path : nil
135
+ images = three_part_images(options_manager, scenario_manager, app_image, payload_path)
133
136
  package = "#{options_manager.package}#{scenario_manager.exe_suffix}"
134
- runtime_sha256 = runtime_path && Digest::SHA256.file(runtime_path).hexdigest
137
+ stitch_three_part(options_manager, bootstrap_path, images, package, payload_path)
138
+ puts "Created tebako #{options_manager.output_type_first} at \"#{package}\""
139
+ end
140
+
141
+ def stitch_three_part(options_manager, bootstrap_path, images, package, payload_path)
135
142
  Tebako::Stitcher.stitch(bootstrap_path, images: images, output: package, lean: true,
136
143
  ruby_version: options_manager.ruby_ver,
137
144
  launcher_abi: Tebako::LauncherAbi::VERSION,
138
- runtime_sha256: runtime_sha256)
139
- puts "Created tebako #{options_manager.output_type_first} at \"#{package}\""
145
+ runtime_sha256: payload_sha256(payload_path))
146
+ end
147
+
148
+ def payload_sha256(payload_path)
149
+ payload_path && Digest::SHA256.file(payload_path).hexdigest
140
150
  end
141
151
 
142
152
  # Validate the options and the packaging environment, then resolve the
143
- # bootstrap (and, for fat, the runtime payload) into the shared cache
153
+ # bootstrap and the runtime into the shared cache. The runtime is needed
154
+ # in both three-part modes: 'fat' embeds it as a payload slot, 'lean'
155
+ # uses its extracted layout to align the application image's arch
156
+ # conventions (and references it in the trailer for first-run resolution)
144
157
  def resolve_three_part_parts(options_manager)
145
158
  options_manager.runtime_source # validates the mode/provenance combination
146
159
  check_bootstrap_version!(options_manager)
147
160
  Tebako::Packager.check_prebuilt_env!(options_manager.stash_dir, options_manager.deps_bin_dir)
148
- runtime_path = fat_runtime_path(options_manager)
161
+ runtime_path = Tebako::RuntimeManager.resolve(options_manager.ruby_ver, options_manager.host_platform)
149
162
  [Tebako::BootstrapManager.resolve(options_manager.host_platform), runtime_path]
150
163
  end
151
164
 
152
- def fat_runtime_path(options_manager)
153
- return nil unless options_manager.fat?
154
-
155
- Tebako::RuntimeManager.resolve(options_manager.ruby_ver, options_manager.host_platform)
156
- end
157
-
158
165
  def three_part_images(options_manager, scenario_manager, app_image, runtime_path)
159
166
  images = [{ path: app_image, mount_point: scenario_manager.fs_mount_point,
160
167
  format_id: Tebako::Stitcher::FORMAT_DWARFS }] + options_manager.images
@@ -190,7 +190,11 @@ module Tebako
190
190
  def configure_commands_not_msys
191
191
  @cmd_suffix = ""
192
192
  @bat_suffix = ""
193
- @force_ruby_platform = "false"
193
+ # Force the ruby (source) platform for gems: precompiled variants link
194
+ # against shared system libraries (libffi & co.) that do not exist
195
+ # inside a tebako package -- e.g. ffi-x86_64-linux-gnu fails to load in
196
+ # the memfs (tebako#343). msys has always forced this.
197
+ @force_ruby_platform = "true"
194
198
  @nokogiri_option = "--no-use-system-libraries"
195
199
  end
196
200
 
@@ -129,16 +129,72 @@ module Tebako
129
129
  # Deploy the application and build its DwarFS image for stitching onto
130
130
  # a prebuilt runtime. Same layout as the bundle-mode image, plus an
131
131
  # entry dispatcher at /local/stub.rb (the runtime's compiled-in entry).
132
- def build_app_image(options_manager, scenario_manager) # rubocop:disable Metrics/AbcSize
132
+ # When layout_dir is given (the resolved runtime's extracted layout),
133
+ # the image's arch conventions are aligned to the runtime's: ruby's
134
+ # compiled-in search paths come from the runtime build, while the
135
+ # local packaging environment names arch directories after the press
136
+ # machine -- on macOS the arch string embeds the kernel version
137
+ # (arm64-darwin23 vs arm64-darwin24), so they differ whenever press
138
+ # and runtime were built on different macOS releases.
139
+ def build_app_image(options_manager, scenario_manager, layout_dir = nil) # rubocop:disable Metrics/AbcSize
133
140
  init(options_manager.stash_dir, options_manager.data_src_dir, options_manager.data_pre_dir,
134
141
  options_manager.data_bin_dir)
135
142
  deploy(options_manager.data_src_dir, options_manager.data_pre_dir, options_manager.rv,
136
143
  options_manager.root, scenario_manager.fs_entrance, options_manager.cwd)
144
+ align_layout_to_runtime!(options_manager.data_src_dir, layout_dir, options_manager.rv) if layout_dir
137
145
  write_entry_dispatcher(options_manager.data_src_dir, scenario_manager, options_manager.cwd)
138
146
  mkdwarfs(options_manager.deps_bin_dir, options_manager.data_bundle_file, options_manager.data_src_dir)
139
147
  options_manager.data_bundle_file
140
148
  end
141
149
 
150
+ # Rename the image's arch directories to the runtime's names and drop
151
+ # in the runtime's own rbconfig.rb. No-op when the conventions already
152
+ # match (always the case off macOS, where the arch string carries no
153
+ # OS version).
154
+ def align_layout_to_runtime!(data_src_dir, layout_dir, ruby_ver)
155
+ align_stdlib_arch!(data_src_dir, layout_dir, ruby_ver.api_version)
156
+ align_gem_ext_arch!(data_src_dir, layout_dir, ruby_ver.api_version)
157
+ end
158
+
159
+ def align_stdlib_arch!(data_src_dir, layout_dir, api_ver)
160
+ runtime_arch = arch_dir_of(File.join(layout_dir, "lib", "ruby", api_ver), "rbconfig.rb")
161
+ image_arch = arch_dir_of(File.join(data_src_dir, "lib", "ruby", api_ver), "rbconfig.rb")
162
+ return if runtime_arch.nil? || image_arch.nil? || runtime_arch == image_arch
163
+
164
+ puts " ... aligning app image layout to the runtime (#{image_arch} -> #{runtime_arch})"
165
+ FileUtils.mv(File.join(data_src_dir, "lib", "ruby", api_ver, image_arch),
166
+ File.join(data_src_dir, "lib", "ruby", api_ver, runtime_arch))
167
+ FileUtils.cp(File.join(layout_dir, "lib", "ruby", api_ver, runtime_arch, "rbconfig.rb"),
168
+ File.join(data_src_dir, "lib", "ruby", api_ver, runtime_arch, "rbconfig.rb"))
169
+ end
170
+
171
+ # Native-gem extensions dir uses the dashed flavor of the arch string
172
+ # (arm64-darwin-23); align it to the runtime's as well
173
+ def align_gem_ext_arch!(data_src_dir, layout_dir, api_ver)
174
+ img_ext = File.join(data_src_dir, "lib", "ruby", "gems", api_ver, "extensions")
175
+ rt_ext = File.join(layout_dir, "lib", "ruby", "gems", api_ver, "extensions")
176
+ runtime_ext = first_dir(rt_ext)
177
+ return if runtime_ext.nil? || !Dir.exist?(img_ext)
178
+
179
+ Dir.children(img_ext).each do |d|
180
+ next if d == runtime_ext || !File.directory?(File.join(img_ext, d))
181
+
182
+ FileUtils.mv(File.join(img_ext, d), File.join(img_ext, runtime_ext))
183
+ end
184
+ end
185
+
186
+ def arch_dir_of(dir, marker)
187
+ return nil unless Dir.exist?(dir)
188
+
189
+ Dir.children(dir).find { |d| File.exist?(File.join(dir, d, marker)) }
190
+ end
191
+
192
+ def first_dir(dir)
193
+ return nil unless Dir.exist?(dir)
194
+
195
+ Dir.children(dir).find { |d| File.directory?(File.join(dir, d)) }
196
+ end
197
+
142
198
  # The prebuilt runtime packages are pressed in 'runtime' mode, so their
143
199
  # compiled-in entry point is /local/stub.rb. A stitched package mounts
144
200
  # the application image as the root filesystem; the dispatcher written
@@ -46,7 +46,14 @@ module Tebako
46
46
  "3.3.6" => "8dc48fffaf270f86f1019053f28e51e4da4cce32a36760a0603a9aee67d7fd8d",
47
47
  "3.3.7" => "9c37c3b12288c7aec20ca121ce76845be5bb5d77662a24919651aaf1d12c8628",
48
48
  "3.4.1" => "3d385e5d22d368b064c817a13ed8e3cc3f71a7705d7ed1bae78013c33aa7c87f",
49
- "3.4.2" => "41328ac21f2bfdd7de6b3565ef4f0dd7543354d37e96f157a1552a6bd0eb364b"
49
+ "3.4.2" => "41328ac21f2bfdd7de6b3565ef4f0dd7543354d37e96f157a1552a6bd0eb364b",
50
+ "4.0.0" => "2e8389c8c072cb658c93a1372732d9eac84082c88b065750db1e52a5ac630271",
51
+ "4.0.1" => "3924be2d05db30f4e35f859bf028be85f4b7dd01714142fd823e4af5de2faf9d",
52
+ "4.0.2" => "51502b26b50b68df4963336ca41e368cde92c928faf91654de4c4c1791f82aac",
53
+ "4.0.3" => "77964acc370d5c8375b9502e5ba6c13c03ef91ab9eb9f521c84fb42b9c9a6b0f",
54
+ "4.0.4" => "f35f6edfa3dabb3f723f9d0cf1906c6512ae77f4e412ab1e68cc6e91d230fa80",
55
+ "4.0.5" => "7d6149079a63f8ae1d326c9fa65c6019ba2dc3155eae7b39159817911c88958e",
56
+ "4.0.6" => "837d299e8f7ddf2be31a229a7a7e019d354979825117989acb3b32b1a9be262a"
50
57
  }.freeze
51
58
 
52
59
  MIN_RUBY_VERSION_WINDOWS = "3.1.6"
@@ -72,38 +79,40 @@ module Tebako
72
79
  @lib_version ||= "#{@ruby_version.split(".")[0..1].join}0"
73
80
  end
74
81
 
82
+ # Version gates compare numerically so 4.x lines fall out naturally
83
+ # (string indexing broke the moment the major version hit 4)
75
84
  def ruby3x?
76
- @ruby3x ||= @ruby_version[0] == "3"
85
+ @ruby3x ||= version_at_least?(3, 0)
77
86
  end
78
87
 
79
88
  def ruby31?
80
- @ruby31 ||= ruby3x? && @ruby_version[2].to_i >= 1
89
+ @ruby31 ||= version_at_least?(3, 1)
81
90
  end
82
91
 
83
92
  def ruby32?
84
- @ruby32 ||= ruby3x? && @ruby_version[2].to_i >= 2
93
+ @ruby32 ||= version_at_least?(3, 2)
85
94
  end
86
95
 
87
96
  def ruby32only?
88
- @ruby32only ||= ruby3x? && @ruby_version[2] == "2"
97
+ @ruby32only ||= major_minor == [3, 2]
89
98
  end
90
99
 
91
100
  def ruby33?
92
- @ruby33 ||= ruby3x? && @ruby_version[2].to_i >= 3
101
+ @ruby33 ||= version_at_least?(3, 3)
93
102
  end
94
103
 
95
104
  def ruby33only?
96
- @ruby33only ||= ruby3x? && @ruby_version[2] == "3"
105
+ @ruby33only ||= major_minor == [3, 3]
97
106
  end
98
107
 
99
108
  def ruby3x7?
100
109
  @ruby3x7 ||= ruby34? ||
101
- (ruby33only? && @ruby_version[4].to_i >= 7) ||
102
- (ruby32only? && @ruby_version[4].to_i >= 7)
110
+ (ruby33only? && patch_version >= 7) ||
111
+ (ruby32only? && patch_version >= 7)
103
112
  end
104
113
 
105
114
  def ruby34?
106
- @ruby34 ||= ruby3x? && @ruby_version[2].to_i >= 4
115
+ @ruby34 ||= version_at_least?(3, 4)
107
116
  end
108
117
 
109
118
  def run_checks
@@ -112,6 +121,22 @@ module Tebako
112
121
  version_check_msys
113
122
  end
114
123
 
124
+ private
125
+
126
+ def major_minor
127
+ @major_minor ||= @ruby_version.split(".").first(2).map(&:to_i)
128
+ end
129
+
130
+ def patch_version
131
+ @patch_version ||= @ruby_version.split(".")[2].to_i
132
+ end
133
+
134
+ def version_at_least?(major, minor)
135
+ (major_minor <=> [major, minor]) >= 0
136
+ end
137
+
138
+ public
139
+
115
140
  def version_check
116
141
  return if RUBY_VERSIONS.key?(@ruby_version)
117
142
 
@@ -31,6 +31,7 @@ require "json"
31
31
  require "net/http"
32
32
  require "uri"
33
33
 
34
+ require_relative "build_helpers"
34
35
  require_relative "error"
35
36
  require_relative "version"
36
37
 
@@ -83,6 +84,10 @@ module Tebako
83
84
  def resolve(ruby_version, platform, tebako_version: Tebako::VERSION)
84
85
  new.resolve(ruby_version, platform, tebako_version: tebako_version)
85
86
  end
87
+
88
+ def layout(runtime_path)
89
+ new.layout(runtime_path)
90
+ end
86
91
  end
87
92
 
88
93
  def initialize(cache_root: nil, mirror: nil, lock_timeout: LOCK_TIMEOUT, retry_delay: RETRY_DELAY)
@@ -105,6 +110,22 @@ module Tebako
105
110
  executable
106
111
  end
107
112
 
113
+ # Extract the runtime package's filesystem layout next to the cached
114
+ # package (idempotent) and return the layout root. The layout is the
115
+ # authoritative source of the runtime's arch conventions (rbconfig
116
+ # location, gem extension dir naming), which the application image must
117
+ # match: ruby's compiled-in search paths come from the runtime build,
118
+ # while a local packaging environment names them after the press machine
119
+ # (macOS embeds the kernel version, e.g. arm64-darwin23 vs -darwin24).
120
+ def layout(runtime_path)
121
+ layout_dir = File.join(File.dirname(runtime_path), "layout")
122
+ return layout_dir if File.directory?(File.join(layout_dir, "lib"))
123
+
124
+ FileUtils.mkdir_p(layout_dir)
125
+ Tebako::BuildHelpers.run_with_capture_v([runtime_path, "--tebako-extract", layout_dir])
126
+ layout_dir
127
+ end
128
+
108
129
  def entries
109
130
  base = File.join(@cache_root, cache_subdir)
110
131
  return [] unless Dir.exist?(base)
@@ -26,5 +26,5 @@
26
26
  # POSSIBILITY OF SUCH DAMAGE.
27
27
 
28
28
  module Tebako
29
- VERSION = "0.15.2"
29
+ VERSION = "0.15.3"
30
30
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tebako
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.2
4
+ version: 0.15.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.