tebako 0.15.1 → 0.15.2
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 +4 -4
- data/CMakeLists.txt +1 -1
- data/README.adoc +9 -4
- data/cmake/tebako-libtfs.cmake +1 -3
- data/include/tebako/tpkg.h +7 -4
- data/lib/tebako/bootstrap_manager.rb +158 -0
- data/lib/tebako/cli.rb +17 -5
- data/lib/tebako/cli_helpers.rb +70 -2
- data/lib/tebako/error.rb +3 -0
- data/lib/tebako/launcher_abi.rb +6 -0
- data/lib/tebako/options_manager.rb +33 -11
- data/lib/tebako/packager/pass1_patch.rb +20 -1
- data/lib/tebako/packager/pass2msys_patch.rb +3 -0
- data/lib/tebako/packager/patch_helpers.rb +3 -1
- data/lib/tebako/runtime_manager.rb +29 -6
- data/lib/tebako/stitcher.rb +22 -6
- data/lib/tebako/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 40cccec56036f14133e05046f858915c7f6ae657c11f3560b647d791c2cc952a
|
|
4
|
+
data.tar.gz: 79022b3acb1d0457a996f671ca93e69ac024107156f31445f27159a1d81ac7da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 318cab0bce4b6528efe1e1c215b473344311f68fcef2bc7ac379cdc81248c06afac942fff0b55a9dd5e45b88f5989031597ef633c4e6e6d69ed2478a83138b13
|
|
7
|
+
data.tar.gz: 0f3b13569b1ffd26de43d6233bfb2579fe91e1d6107b51370562c64e2f0f87021813bb1129eaafaae9f68202e0c37d9d03cf9d439ce5610ff857493278fe6838
|
data/CMakeLists.txt
CHANGED
|
@@ -175,7 +175,7 @@ string(CONCAT RUBY_API_VER ${RUBY_VER_BASE} ".0")
|
|
|
175
175
|
# NOTE: the env override in def_ext_prj_g (tebako-tools) is currently broken
|
|
176
176
|
# (`if (DEFINED ENV{${TAG})` is missing a closing brace, so the test never
|
|
177
177
|
# fires); this default is the operative tag selection.
|
|
178
|
-
def_ext_prj_g(DWARFS_WR "v0.12.
|
|
178
|
+
def_ext_prj_g(DWARFS_WR "v0.12.9")
|
|
179
179
|
|
|
180
180
|
# Provisions libtfs (prebuilt package or vcpkg toolchain for the source
|
|
181
181
|
# build), the prebuilt mkdwarfs, and -- for the prebuilt path -- the
|
data/README.adoc
CHANGED
|
@@ -420,7 +420,7 @@ tebako press \
|
|
|
420
420
|
[-c|--cwd=<package-current-working-directory>] \
|
|
421
421
|
[-D|--devmode] \
|
|
422
422
|
[-P|--patchelf] \
|
|
423
|
-
[-m|--mode=<bundle|both|application|runtime>] \
|
|
423
|
+
[-m|--mode=<lean|fat|classic|bundle|both|application|runtime>] \
|
|
424
424
|
[-u|--ref=<runtime-reference>] \
|
|
425
425
|
[-t|--tebafile=<path-to-tebafile>]
|
|
426
426
|
----
|
|
@@ -452,6 +452,7 @@ On Windows, the output file is automatically appended the `.exe` extension.
|
|
|
452
452
|
|
|
453
453
|
*** in `runtime` mode, the runtime package is created at `tebako-runtime`.
|
|
454
454
|
*** in `application` mode, the application package is created at `<current-folder>/<entry-point-base-name>`.
|
|
455
|
+
*** in `lean`, `fat` and `classic` modes, the package is created at `<current-folder>/<entry-point-base-name>`.
|
|
455
456
|
*** in `bundle` mode, the bundled package is created at `<current-folder>/<entry-point-base-name>`.
|
|
456
457
|
*** in `both` mode, the runtime package is created at `<current-folder>/<entry-point-base-name>`,
|
|
457
458
|
and the application package is created at `<current-folder>/<entry-point-base-name>.tebako`.
|
|
@@ -460,6 +461,7 @@ and the application package is created at `<current-folder>/<entry-point-base-na
|
|
|
460
461
|
|
|
461
462
|
*** in `runtime` mode, the runtime package is named according to the `-o` option.
|
|
462
463
|
*** in `application` mode, the application package is named according to the `-o` option.
|
|
464
|
+
*** in `lean`, `fat` and `classic` modes, the package is named according to the `-o` option.
|
|
463
465
|
*** in `bundle` mode, the bundled package is named according to the `-o` option.
|
|
464
466
|
*** in `both` mode, the runtime package is named according to the `-o` option,
|
|
465
467
|
and the application package is named according to the `-o` option with the `.tebako` extension.
|
|
@@ -502,10 +504,13 @@ For example, a package created at Ubuntu 20 system can be used on Ubuntu 22.
|
|
|
502
504
|
NOTE: The feature is exeprimental, we may consider another approach in the future.
|
|
503
505
|
|
|
504
506
|
`--mode=<mode>`::
|
|
505
|
-
(optional, defaults to `
|
|
506
|
-
Package output mode, determines
|
|
507
|
-
|
|
507
|
+
(optional, defaults to `lean`)
|
|
508
|
+
Package output mode, determines the package layout (three-part or runtime-stitched)
|
|
509
|
+
and whether the runtime and/or application are separately packaged.
|
|
508
510
|
|
|
511
|
+
`lean`::: Create a three-part package: the tebako-bootstrap launcher plus the application image slot(s) and a tpkg manifest trailer carrying the runtime reference. At first run the bootstrap resolves (downloads, verifies and caches) the referenced prebuilt runtime into the machine-wide cache (`~/.tebako` or `$TEBAKO_HOME`); subsequent runs of any lean package built for the same runtime share that cache entry. The output file is named according to the `-o` option.
|
|
512
|
+
`fat`::: Like `lean`, but the runtime package is also embedded as a payload slot. The first run installs it into the cache without network access (works with `TEBAKO_OFFLINE=1`). The output file is named according to the `-o` option.
|
|
513
|
+
`classic`::: Stitch the application image onto a prebuilt runtime package (the Stage-3A layout; identical to `bundle` with the default `--runtime prebuilt`). The output file is named according to the `-o` option.
|
|
509
514
|
`bundle`::: Create a single package bundling both the runtime and application. The output file is named according to the `-o` option.
|
|
510
515
|
`both`::: Create separate packages for the runtime and application. Outputs two separate files: one for the runtime at the location specified at the `-o {filename}` and one for the application at `{filename}.package`.
|
|
511
516
|
`application`::: Create the application package only. The output file is named according to the `-o` option.
|
data/cmake/tebako-libtfs.cmake
CHANGED
|
@@ -82,9 +82,7 @@ endif()
|
|
|
82
82
|
if(IS_GNU)
|
|
83
83
|
set(LIBTFS_PLATFORM "linux-gnu-${__LIBTFS_ARCH}")
|
|
84
84
|
elseif(IS_MUSL)
|
|
85
|
-
|
|
86
|
-
message(FATAL_ERROR "No prebuilt libtfs package for linux-musl-${__LIBTFS_ARCH}; use -DDWARFS_PRELOAD=OFF (source build)")
|
|
87
|
-
endif()
|
|
85
|
+
# musl-arm64 prebuilt packages first ship in libtfs v0.12.9
|
|
88
86
|
set(LIBTFS_PLATFORM "linux-musl-${__LIBTFS_ARCH}")
|
|
89
87
|
elseif(IS_DARWIN)
|
|
90
88
|
set(LIBTFS_PLATFORM "macos-${__LIBTFS_ARCH}")
|
data/include/tebako/tpkg.h
CHANGED
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
* offset size field
|
|
49
49
|
* 0 8 u64 offset (image start, absolute file offset)
|
|
50
50
|
* 8 8 u64 size (image length in bytes)
|
|
51
|
-
* 16 4 u32 format_id (0=auto(magic), 1=dwarfs, 2=squashfs, 3=zip)
|
|
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)
|
|
53
|
+
* 24 256 char mount_point[256] (UTF-8, NUL-padded; empty for runtime payloads)
|
|
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
|
|
@@ -108,6 +108,9 @@ 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 */
|
|
113
|
+
#define TPKG_FORMAT_RUNTIME 4u
|
|
111
114
|
|
|
112
115
|
/* ---- error codes (returned by tpkg_errno) -------------------------------- */
|
|
113
116
|
|
|
@@ -157,7 +160,7 @@ int tpkg_read_mem(const void* data, size_t size, tpkg_manifest* out);
|
|
|
157
160
|
int tpkg_write_fd(int fd, const tpkg_manifest* m);
|
|
158
161
|
|
|
159
162
|
/* Magic-independent structural checks: version supported, slot_count in
|
|
160
|
-
* 1..TPKG_MAX_SLOTS, offset+size non-overflowing, format_id <=
|
|
163
|
+
* 1..TPKG_MAX_SLOTS, offset+size non-overflowing, format_id <= TPKG_FORMAT_RUNTIME,
|
|
161
164
|
* runtime_ref and mount_points NUL-terminated within their fixed fields. */
|
|
162
165
|
int tpkg_validate(const tpkg_manifest* m);
|
|
163
166
|
|
|
@@ -397,7 +400,7 @@ int tpkg_validate(const tpkg_manifest* m)
|
|
|
397
400
|
if (s->size > UINT64_MAX - s->offset) {
|
|
398
401
|
return tpkg__fail(TPKG_ERR_INVALID);
|
|
399
402
|
}
|
|
400
|
-
if (s->format_id >
|
|
403
|
+
if (s->format_id > TPKG_FORMAT_RUNTIME) {
|
|
401
404
|
return tpkg__fail(TPKG_ERR_INVALID);
|
|
402
405
|
}
|
|
403
406
|
if (tpkg__strnlen(s->mount_point, TPKG_MOUNT_POINT_LEN) == TPKG_MOUNT_POINT_LEN) {
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of the Tebako project.
|
|
6
|
+
#
|
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
|
8
|
+
# modification, are permitted provided that the following conditions
|
|
9
|
+
# are met:
|
|
10
|
+
# 1. Redistributions of source code must retain the above copyright
|
|
11
|
+
# notice, this list of conditions and the following disclaimer.
|
|
12
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
|
15
|
+
#
|
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
17
|
+
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
18
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
19
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
|
20
|
+
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
21
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
22
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
23
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
24
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
25
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
|
|
28
|
+
require_relative "runtime_manager"
|
|
29
|
+
|
|
30
|
+
# Tebako - an executable packager
|
|
31
|
+
module Tebako
|
|
32
|
+
# Resolution, download, verification and machine-wide caching of the
|
|
33
|
+
# tebako-bootstrap launcher binaries published by tamatebako/tebako-bootstrap.
|
|
34
|
+
# The launcher is the base binary of lean/fat three-part packages.
|
|
35
|
+
#
|
|
36
|
+
# Cache layout (rooted at $TEBAKO_HOME or ~/.tebako, shared with the
|
|
37
|
+
# runtime package cache):
|
|
38
|
+
# bootstraps/tebako-bootstrap-<version>-<platform>/
|
|
39
|
+
# tebako-bootstrap-<version>-<platform>[.exe]
|
|
40
|
+
# sha256 -- digest the installed file was verified against
|
|
41
|
+
# origin -- URL the binary was downloaded from
|
|
42
|
+
#
|
|
43
|
+
# All download/verify/lock machinery is inherited from RuntimeManager; only
|
|
44
|
+
# the release-shape specifics (asset naming, manifest.json object format,
|
|
45
|
+
# SHA256SUMS index name, mirror env var) differ.
|
|
46
|
+
class BootstrapManager < RuntimeManager
|
|
47
|
+
DEFAULT_MIRROR = "https://github.com/tamatebako/tebako-bootstrap/releases/download"
|
|
48
|
+
BOOTSTRAPS_DIR = "bootstraps"
|
|
49
|
+
INDEX_FILES = ["manifest.json", "SHA256SUMS"].freeze
|
|
50
|
+
|
|
51
|
+
# tebako-bootstrap release consumed by default (TEBAKO_BOOTSTRAP_VERSION
|
|
52
|
+
# overrides). 0.2.0 is the first release that installs a fat package's
|
|
53
|
+
# runtime payload slot into the cache at first run.
|
|
54
|
+
BOOTSTRAP_VERSION = "0.2.0"
|
|
55
|
+
PAYLOAD_MIN_VERSION = "0.2.0"
|
|
56
|
+
|
|
57
|
+
class << self
|
|
58
|
+
def default_version
|
|
59
|
+
version = ENV.fetch("TEBAKO_BOOTSTRAP_VERSION", nil)
|
|
60
|
+
version.nil? || version.empty? ? BOOTSTRAP_VERSION : version.sub(/\Av/, "")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def resolve(platform, bootstrap_version: default_version)
|
|
64
|
+
new.resolve(platform, bootstrap_version: bootstrap_version)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def resolve(platform, bootstrap_version: self.class.default_version)
|
|
69
|
+
super(bootstrap_version, platform, tebako_version: bootstrap_version)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def default_mirror
|
|
75
|
+
DEFAULT_MIRROR
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def mirror_env_var
|
|
79
|
+
"TEBAKO_BOOTSTRAP_MIRROR"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def index_files
|
|
83
|
+
INDEX_FILES
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def cache_subdir
|
|
87
|
+
BOOTSTRAPS_DIR
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def release_name
|
|
91
|
+
"tebako-bootstrap"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def entry_dir(_version, platform, bootstrap_version)
|
|
95
|
+
File.join(@cache_root, BOOTSTRAPS_DIR, "tebako-bootstrap-#{bootstrap_version}-#{platform}")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def runtime_filename(_version, platform, bootstrap_version)
|
|
99
|
+
suffix = platform.start_with?("windows") ? ".exe" : ""
|
|
100
|
+
"tebako-bootstrap-#{bootstrap_version}-#{platform}#{suffix}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def runtime_ref(_version, platform, bootstrap_version)
|
|
104
|
+
"tebako-bootstrap@#{bootstrap_version} (#{platform})"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def find_entry(index, _version, platform, bootstrap_version)
|
|
108
|
+
entry = index.find { |candidate| candidate["platform"] == platform }
|
|
109
|
+
return entry if entry
|
|
110
|
+
|
|
111
|
+
platforms = index.map { |candidate| candidate["platform"] }
|
|
112
|
+
Tebako.packaging_error(131, "no tebako-bootstrap package for #{platform} (bootstrap #{bootstrap_version}). " \
|
|
113
|
+
"Available: #{platforms.join(", ")}.")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def offline_check(ref, bootstrap_version)
|
|
117
|
+
return unless offline?
|
|
118
|
+
|
|
119
|
+
Tebako.packaging_error(132, "#{ref} is not cached and downloads are disabled " \
|
|
120
|
+
"(release index: #{index_urls(bootstrap_version).join(", ")}; " \
|
|
121
|
+
"#{mirror_env_var}=#{@mirror})")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# tebako-bootstrap's manifest.json is an object
|
|
125
|
+
# ({name:, version:, assets: [{platform:, file:, sha256:}]}), not the
|
|
126
|
+
# entry array tebako-runtime-ruby publishes
|
|
127
|
+
def parse_manifest(body, _bootstrap_version)
|
|
128
|
+
manifest_assets(body)
|
|
129
|
+
.select { |asset| asset["platform"] && asset["file"] && asset["sha256"] }
|
|
130
|
+
.map { |asset| manifest_entry(asset) }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def manifest_assets(body)
|
|
134
|
+
data = JSON.parse(body)
|
|
135
|
+
assets = data.is_a?(Hash) ? data["assets"] : nil
|
|
136
|
+
raise IndexUnavailable, "manifest.json has no assets array" unless assets.is_a?(Array)
|
|
137
|
+
|
|
138
|
+
assets
|
|
139
|
+
rescue JSON::ParserError
|
|
140
|
+
raise IndexUnavailable, "manifest.json is not valid JSON"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def manifest_entry(asset)
|
|
144
|
+
{ "platform" => asset["platform"], "filename" => asset["file"], "sha256" => asset["sha256"].downcase }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def parse_sha256sums(body, bootstrap_version)
|
|
148
|
+
pattern = /\Atebako-bootstrap-#{Regexp.escape(bootstrap_version)}-(.+?)(?:\.exe)?\z/
|
|
149
|
+
body.each_line.filter_map do |line|
|
|
150
|
+
sha256, file = line.strip.split(/\s+/, 2)
|
|
151
|
+
match = file && pattern.match(file.sub(/\A\*/, ""))
|
|
152
|
+
next unless match
|
|
153
|
+
|
|
154
|
+
{ "platform" => match[1], "filename" => file.sub(/\A\*/, ""), "sha256" => sha256.downcase }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
data/lib/tebako/cli.rb
CHANGED
|
@@ -174,9 +174,10 @@ module Tebako
|
|
|
174
174
|
DESC
|
|
175
175
|
|
|
176
176
|
RUNTIME_DESCRIPTION = <<~DESC
|
|
177
|
-
Runtime provenance: 'prebuilt' resolves/downloads a prebuilt tebako runtime package
|
|
178
|
-
#{" " * 65}#
|
|
179
|
-
#{" " * 65}#
|
|
177
|
+
Runtime provenance: 'prebuilt' resolves/downloads a prebuilt tebako runtime package (default for the
|
|
178
|
+
#{" " * 65}# 'bundle', 'classic', 'lean' and 'fat' modes); 'source' keeps the Stage-2 source build
|
|
179
|
+
#{" " * 65}# (not available for 'lean'/'fat' -- the bootstrap resolves tebako-runtime-ruby releases
|
|
180
|
+
#{" " * 65}# at run time). Modes other than those always build from source.
|
|
180
181
|
DESC
|
|
181
182
|
|
|
182
183
|
IMAGE_DESCRIPTION = <<~DESC
|
|
@@ -184,6 +185,16 @@ module Tebako
|
|
|
184
185
|
#{" " * 65}# must be distinct. Prebuilt runtime only.
|
|
185
186
|
DESC
|
|
186
187
|
|
|
188
|
+
MODE_DESCRIPTION = <<~DESC
|
|
189
|
+
Tebako press mode, 'lean' by default.
|
|
190
|
+
#{" " * 65}# 'lean' presses a three-part package (tebako-bootstrap + application image(s) + tpkg trailer);
|
|
191
|
+
#{" " * 65}# the runtime is resolved into the shared cache at first run.
|
|
192
|
+
#{" " * 65}# 'fat' is 'lean' plus the runtime package as a payload slot -- the first run installs it
|
|
193
|
+
#{" " * 65}# into the cache without network access.
|
|
194
|
+
#{" " * 65}# 'classic' stitches the application image onto a prebuilt runtime (Stage-3A layout);
|
|
195
|
+
#{" " * 65}# 'bundle', 'both', 'application' and 'runtime' keep their legacy behaviors.
|
|
196
|
+
DESC
|
|
197
|
+
|
|
187
198
|
desc "press", "Press tebako image"
|
|
188
199
|
method_option :cwd, type: :string, aliases: "-c", required: false, desc: CWD_DESCRIPTION
|
|
189
200
|
method_option :"log-level", type: :string, aliases: "-l", required: false, enum: %w[error warn debug trace],
|
|
@@ -197,8 +208,9 @@ module Tebako
|
|
|
197
208
|
enum: Tebako::RubyVersion::RUBY_VERSIONS.keys,
|
|
198
209
|
desc: "Tebako package Ruby version, #{Tebako::RubyVersion::DEFAULT_RUBY_VERSION} by default"
|
|
199
210
|
method_option :patchelf, aliases: "-P", type: :boolean, desc: RGP_DESCRIPTION
|
|
200
|
-
method_option :mode, type: :string, aliases: "-m", required: false,
|
|
201
|
-
|
|
211
|
+
method_option :mode, type: :string, aliases: "-m", required: false,
|
|
212
|
+
enum: %w[lean fat classic bundle both runtime application],
|
|
213
|
+
desc: MODE_DESCRIPTION
|
|
202
214
|
method_option :ref, type: :string, aliases: "-u", required: false, desc: REF_DESCRIPTION
|
|
203
215
|
method_option :runtime, type: :string, required: false, enum: %w[prebuilt source], desc: RUNTIME_DESCRIPTION
|
|
204
216
|
method_option :"build-runtime", type: :boolean, required: false,
|
data/lib/tebako/cli_helpers.rb
CHANGED
|
@@ -25,13 +25,16 @@
|
|
|
25
25
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
26
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
|
|
28
|
+
require "digest"
|
|
28
29
|
require "etc"
|
|
29
30
|
require "fileutils"
|
|
30
31
|
require "pathname"
|
|
31
32
|
require "rbconfig"
|
|
32
33
|
|
|
34
|
+
require_relative "bootstrap_manager"
|
|
33
35
|
require_relative "codegen"
|
|
34
36
|
require_relative "error"
|
|
37
|
+
require_relative "launcher_abi"
|
|
35
38
|
require_relative "options_manager"
|
|
36
39
|
require_relative "runtime_manager"
|
|
37
40
|
require_relative "scenario_manager"
|
|
@@ -86,8 +89,13 @@ module Tebako
|
|
|
86
89
|
options_manager.process_gemfile(scenario_manager.gemfile_path) if scenario_manager.with_gemfile
|
|
87
90
|
check_warnings(options_manager)
|
|
88
91
|
puts options_manager.press_announce(scenario_manager.msys?)
|
|
92
|
+
dispatch_press(options_manager, scenario_manager)
|
|
93
|
+
end
|
|
89
94
|
|
|
90
|
-
|
|
95
|
+
def dispatch_press(options_manager, scenario_manager)
|
|
96
|
+
if options_manager.three_part?
|
|
97
|
+
do_press_three_part(options_manager, scenario_manager)
|
|
98
|
+
elsif options_manager.prebuilt_runtime?
|
|
91
99
|
do_press_prebuilt(options_manager, scenario_manager)
|
|
92
100
|
else
|
|
93
101
|
do_press_source(options_manager, scenario_manager)
|
|
@@ -113,6 +121,66 @@ module Tebako
|
|
|
113
121
|
puts "Created tebako #{options_manager.output_type_first} at \"#{package}\""
|
|
114
122
|
end
|
|
115
123
|
|
|
124
|
+
# Press a three-part package (Stage 3B): tebako-bootstrap + application
|
|
125
|
+
# image slot(s) + tpkg trailer with the runtime reference (launcher ABI
|
|
126
|
+
# v1). 'lean' (the default) resolves the runtime into the shared cache at
|
|
127
|
+
# first run; 'fat' additionally embeds the runtime package as a payload
|
|
128
|
+
# slot, so the first run installs it without any network access.
|
|
129
|
+
def do_press_three_part(options_manager, scenario_manager)
|
|
130
|
+
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)
|
|
133
|
+
package = "#{options_manager.package}#{scenario_manager.exe_suffix}"
|
|
134
|
+
runtime_sha256 = runtime_path && Digest::SHA256.file(runtime_path).hexdigest
|
|
135
|
+
Tebako::Stitcher.stitch(bootstrap_path, images: images, output: package, lean: true,
|
|
136
|
+
ruby_version: options_manager.ruby_ver,
|
|
137
|
+
launcher_abi: Tebako::LauncherAbi::VERSION,
|
|
138
|
+
runtime_sha256: runtime_sha256)
|
|
139
|
+
puts "Created tebako #{options_manager.output_type_first} at \"#{package}\""
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Validate the options and the packaging environment, then resolve the
|
|
143
|
+
# bootstrap (and, for fat, the runtime payload) into the shared cache
|
|
144
|
+
def resolve_three_part_parts(options_manager)
|
|
145
|
+
options_manager.runtime_source # validates the mode/provenance combination
|
|
146
|
+
check_bootstrap_version!(options_manager)
|
|
147
|
+
Tebako::Packager.check_prebuilt_env!(options_manager.stash_dir, options_manager.deps_bin_dir)
|
|
148
|
+
runtime_path = fat_runtime_path(options_manager)
|
|
149
|
+
[Tebako::BootstrapManager.resolve(options_manager.host_platform), runtime_path]
|
|
150
|
+
end
|
|
151
|
+
|
|
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
|
+
def three_part_images(options_manager, scenario_manager, app_image, runtime_path)
|
|
159
|
+
images = [{ path: app_image, mount_point: scenario_manager.fs_mount_point,
|
|
160
|
+
format_id: Tebako::Stitcher::FORMAT_DWARFS }] + options_manager.images
|
|
161
|
+
images << { path: runtime_path, mount_point: "", format_id: Tebako::Stitcher::FORMAT_RUNTIME } if runtime_path
|
|
162
|
+
images
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# The fat payload slot is installed by the bootstrap at first run — a
|
|
166
|
+
# capability added in tebako-bootstrap 0.2.0
|
|
167
|
+
def check_bootstrap_version!(options_manager)
|
|
168
|
+
return unless options_manager.fat?
|
|
169
|
+
|
|
170
|
+
version = Tebako::BootstrapManager.default_version
|
|
171
|
+
minimum = Tebako::BootstrapManager::PAYLOAD_MIN_VERSION
|
|
172
|
+
return if payload_capable?(version, minimum)
|
|
173
|
+
|
|
174
|
+
Tebako.packaging_error(134, "fat mode requires tebako-bootstrap >= #{minimum} (selected: #{version}; " \
|
|
175
|
+
"set TEBAKO_BOOTSTRAP_VERSION to a payload-capable release)")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def payload_capable?(version, minimum)
|
|
179
|
+
Gem::Version.new(version) >= Gem::Version.new(minimum)
|
|
180
|
+
rescue ArgumentError
|
|
181
|
+
false
|
|
182
|
+
end
|
|
183
|
+
|
|
116
184
|
def do_press_application(options_manager, scenario_manager)
|
|
117
185
|
return unless %w[both application].include?(options_manager.mode)
|
|
118
186
|
|
|
@@ -121,7 +189,7 @@ module Tebako
|
|
|
121
189
|
end
|
|
122
190
|
|
|
123
191
|
def do_press_runtime(options_manager, scenario_manager)
|
|
124
|
-
return unless %w[both runtime bundle].include?(options_manager.mode)
|
|
192
|
+
return unless %w[both runtime bundle classic].include?(options_manager.mode)
|
|
125
193
|
|
|
126
194
|
generate_files(options_manager, scenario_manager)
|
|
127
195
|
merged_env = ENV.to_h.merge(scenario_manager.b_env)
|
data/lib/tebako/error.rb
CHANGED
|
@@ -57,6 +57,9 @@ module Tebako
|
|
|
57
57
|
127 => "Stitch input file is not accessible",
|
|
58
58
|
128 => "Prebuilt runtime press requires the packaging environment (run 'tebako setup' first)",
|
|
59
59
|
130 => "Option combination is not supported",
|
|
60
|
+
131 => "No tebako-bootstrap package for the requested platform",
|
|
61
|
+
132 => "TEBAKO_OFFLINE is set and the requested tebako-bootstrap package is not cached",
|
|
62
|
+
134 => "Fat mode requires a payload-capable tebako-bootstrap release",
|
|
60
63
|
201 => "Warning. Could not create cache version file"
|
|
61
64
|
}.freeze
|
|
62
65
|
|
data/lib/tebako/launcher_abi.rb
CHANGED
|
@@ -30,6 +30,12 @@ module Tebako
|
|
|
30
30
|
# three-part package model (spec §4.4).
|
|
31
31
|
#
|
|
32
32
|
# A lean package is [tebako-bootstrap][.tfs image slots][tpkg trailer].
|
|
33
|
+
# A fat package has the same layout plus the runtime package itself as a
|
|
34
|
+
# payload slot (format_id TPKG_FORMAT_RUNTIME, empty mount point,
|
|
35
|
+
# ";sha256=<hex>" appended to the trailer's runtime_ref): at first run the
|
|
36
|
+
# bootstrap installs the payload into the shared cache instead of
|
|
37
|
+
# downloading it. Payload slots are never handed over as --tebako-image.
|
|
38
|
+
#
|
|
33
39
|
# The bootstrap (tamatebako/tebako-bootstrap) parses the trailer of its own
|
|
34
40
|
# executable, resolves the language runtime into the shared cache, and
|
|
35
41
|
# execs it as:
|
|
@@ -41,6 +41,13 @@ require_relative "version"
|
|
|
41
41
|
module Tebako
|
|
42
42
|
# Cli helpers
|
|
43
43
|
class OptionsManager # rubocop:disable Metrics/ClassLength
|
|
44
|
+
# Press modes producing three-part packages (tebako-bootstrap + image
|
|
45
|
+
# slots + tpkg trailer): 'lean' resolves the runtime at first run, 'fat'
|
|
46
|
+
# additionally embeds it as a payload slot (self-installing, offline)
|
|
47
|
+
THREE_PART_MODES = %w[lean fat].freeze
|
|
48
|
+
# Modes whose default runtime provenance is a prebuilt runtime package
|
|
49
|
+
PREBUILT_DEFAULT_MODES = %w[bundle classic lean fat].freeze
|
|
50
|
+
|
|
44
51
|
def initialize(options)
|
|
45
52
|
@options = options
|
|
46
53
|
@rv = Tebako::RubyVersion.new(@options["Ruby"])
|
|
@@ -157,14 +164,24 @@ module Tebako
|
|
|
157
164
|
end
|
|
158
165
|
|
|
159
166
|
def mode
|
|
160
|
-
@mode ||= @options["mode"].nil? ? "
|
|
167
|
+
@mode ||= @options["mode"].nil? ? "lean" : @options["mode"]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def three_part?
|
|
171
|
+
THREE_PART_MODES.include?(mode)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def fat?
|
|
175
|
+
mode == "fat"
|
|
161
176
|
end
|
|
162
177
|
|
|
163
178
|
# Runtime provenance: "prebuilt" (resolve/download a prebuilt runtime
|
|
164
|
-
# package
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
179
|
+
# package) or "source" (the Stage-2 source build). Default is "prebuilt"
|
|
180
|
+
# for the bundle/classic/lean/fat modes; other modes always build from
|
|
181
|
+
# source, and --build-runtime forces the source path everywhere it is
|
|
182
|
+
# allowed (back-compat alias for '--runtime source'). The three-part
|
|
183
|
+
# modes (lean/fat) require prebuilt runtime packages: the bootstrap
|
|
184
|
+
# resolves tebako-runtime-ruby releases at run time.
|
|
168
185
|
def runtime_source
|
|
169
186
|
@runtime_source ||= checked_runtime_source(requested_runtime_source)
|
|
170
187
|
end
|
|
@@ -246,7 +263,7 @@ module Tebako
|
|
|
246
263
|
press_announce_application(is_msys)
|
|
247
264
|
when "both"
|
|
248
265
|
press_announce_both
|
|
249
|
-
when "bundle"
|
|
266
|
+
when "bundle", "classic", "lean", "fat"
|
|
250
267
|
press_announce_bundle
|
|
251
268
|
when "runtime"
|
|
252
269
|
press_announce_runtime
|
|
@@ -290,7 +307,7 @@ module Tebako
|
|
|
290
307
|
def press_announce_bundle
|
|
291
308
|
<<~ANN
|
|
292
309
|
Running tebako press at #{prefix}
|
|
293
|
-
Mode: '
|
|
310
|
+
Mode: '#{mode}'
|
|
294
311
|
Ruby version: '#{@ruby_ver}'
|
|
295
312
|
Project root: '#{root}'
|
|
296
313
|
Application entry point: '#{fs_entrance}'
|
|
@@ -374,14 +391,19 @@ module Tebako
|
|
|
374
391
|
def requested_runtime_source
|
|
375
392
|
explicit = @options["runtime"]
|
|
376
393
|
return "source" if @options["build-runtime"]
|
|
377
|
-
return mode
|
|
394
|
+
return PREBUILT_DEFAULT_MODES.include?(mode) ? "prebuilt" : "source" if explicit.nil?
|
|
378
395
|
|
|
379
396
|
explicit
|
|
380
397
|
end
|
|
381
398
|
|
|
382
399
|
def checked_runtime_source(source)
|
|
383
|
-
if source == "prebuilt" && mode
|
|
384
|
-
Tebako.packaging_error(130, "--runtime prebuilt is supported in bundle
|
|
400
|
+
if source == "prebuilt" && !PREBUILT_DEFAULT_MODES.include?(mode)
|
|
401
|
+
Tebako.packaging_error(130, "--runtime prebuilt is supported in bundle, classic, lean and fat modes only " \
|
|
402
|
+
"(mode: '#{mode}')")
|
|
403
|
+
end
|
|
404
|
+
if source == "source" && three_part?
|
|
405
|
+
Tebako.packaging_error(130, "mode '#{mode}' requires a prebuilt runtime package " \
|
|
406
|
+
"(the bootstrap resolves tebako-runtime-ruby releases at first run)")
|
|
385
407
|
end
|
|
386
408
|
source
|
|
387
409
|
end
|
|
@@ -399,7 +421,7 @@ module Tebako
|
|
|
399
421
|
|
|
400
422
|
def host_arch_id(arch)
|
|
401
423
|
case arch
|
|
402
|
-
when /^(x86_64|amd64)$/ then "x86_64"
|
|
424
|
+
when /^(x86_64|amd64|x64)$/ then "x86_64"
|
|
403
425
|
when /^(aarch64|arm64)$/ then "arm64"
|
|
404
426
|
else
|
|
405
427
|
Tebako.packaging_error(112, arch)
|
|
@@ -203,6 +203,21 @@ module Tebako
|
|
|
203
203
|
"/* tebako patched */ static const struct vktable *console_win32_vk(const char *, size_t);"
|
|
204
204
|
}.freeze
|
|
205
205
|
|
|
206
|
+
# Ruby's win32.c defines clock_gettime/clock_getres fallbacks with no
|
|
207
|
+
# HAVE_* configure guard (at least through 3.4); modern mingw-w64
|
|
208
|
+
# winpthreads headers (pthread_time.h, pulled in by time.h) carry
|
|
209
|
+
# static-inline definitions of the same symbols, so the toolchain
|
|
210
|
+
# build fails with redefinition errors. Rename ruby's fallbacks
|
|
211
|
+
# before the toolchain build; the CRT/winpthreads implementations
|
|
212
|
+
# (which configure detects) serve the calls. Pass2 re-applies the
|
|
213
|
+
# same rename from pristine sources for the final build.
|
|
214
|
+
WIN32_WIN32_C_CLOCK_PATCH = {
|
|
215
|
+
"clock_gettime(clockid_t clock_id, struct timespec *sp)" =>
|
|
216
|
+
"_dummy_clock_gettime(clockid_t clock_id, struct timespec *sp)",
|
|
217
|
+
"clock_getres(clockid_t clock_id, struct timespec *sp)" =>
|
|
218
|
+
"_dummy_clock_getres(clockid_t clock_id, struct timespec *sp)"
|
|
219
|
+
}.freeze
|
|
220
|
+
|
|
206
221
|
def patch_map
|
|
207
222
|
pm = msys_patches
|
|
208
223
|
pm.merge!(super)
|
|
@@ -246,7 +261,11 @@ module Tebako
|
|
|
246
261
|
"ext/openssl/extconf.rb" => OPENSSL_EXTCONF_RB_PATCH,
|
|
247
262
|
# ....................................................
|
|
248
263
|
# Fix the signature of console_win32_vk
|
|
249
|
-
"ext/io/console/win32_vk.inc" => EXT_IO_CONSOLE_WIN32_VK_INC_PATCH
|
|
264
|
+
"ext/io/console/win32_vk.inc" => EXT_IO_CONSOLE_WIN32_VK_INC_PATCH,
|
|
265
|
+
# ....................................................
|
|
266
|
+
# Rename ruby's clock_gettime/clock_getres fallbacks before the
|
|
267
|
+
# toolchain build (winpthreads static-inline collision)
|
|
268
|
+
"win32/win32.c" => WIN32_WIN32_C_CLOCK_PATCH
|
|
250
269
|
}
|
|
251
270
|
end
|
|
252
271
|
|
|
@@ -114,6 +114,9 @@ module Tebako
|
|
|
114
114
|
"#if defined _MSC_VER && _MSC_VER <= 1200" =>
|
|
115
115
|
"#{PatchLiterals::C_FILE_SUBST_LESS}\n#if defined _MSC_VER && _MSC_VER <= 1200",
|
|
116
116
|
"len = GetCurrentDirectoryW(0, NULL);" => WIN32_WIN32_C_MSYS_SUBST,
|
|
117
|
+
# Keep the clock renames in sync with Pass1MSysPatch::WIN32_WIN32_C_CLOCK_PATCH:
|
|
118
|
+
# pass1 applies them for the toolchain build, this pass re-applies them
|
|
119
|
+
# from pristine sources for the final build
|
|
117
120
|
"clock_gettime(clockid_t clock_id, struct timespec *sp)" =>
|
|
118
121
|
"_dummy_clock_gettime(clockid_t clock_id, struct timespec *sp)",
|
|
119
122
|
"clock_getres(clockid_t clock_id, struct timespec *sp)" =>
|
|
@@ -76,7 +76,9 @@ module Tebako
|
|
|
76
76
|
|
|
77
77
|
def recreate(dirname)
|
|
78
78
|
FileUtils.rm_rf(dirname, noop: nil, verbose: nil, secure: true)
|
|
79
|
-
|
|
79
|
+
# mkdir_p: in three-part/prebuilt press flows no cmake configure runs,
|
|
80
|
+
# so the parent output folder may not exist yet
|
|
81
|
+
FileUtils.mkdir_p(dirname)
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
def restore_and_save(fname, strict: true)
|
|
@@ -87,7 +87,7 @@ module Tebako
|
|
|
87
87
|
|
|
88
88
|
def initialize(cache_root: nil, mirror: nil, lock_timeout: LOCK_TIMEOUT, retry_delay: RETRY_DELAY)
|
|
89
89
|
@cache_root = cache_root || self.class.default_cache_root
|
|
90
|
-
@mirror = (mirror || ENV.fetch(
|
|
90
|
+
@mirror = (mirror || ENV.fetch(mirror_env_var, nil) || default_mirror).sub(%r{/+\z}, "")
|
|
91
91
|
@lock_timeout = lock_timeout
|
|
92
92
|
@retry_delay = retry_delay
|
|
93
93
|
end
|
|
@@ -106,7 +106,7 @@ module Tebako
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def entries
|
|
109
|
-
base = File.join(@cache_root,
|
|
109
|
+
base = File.join(@cache_root, cache_subdir)
|
|
110
110
|
return [] unless Dir.exist?(base)
|
|
111
111
|
|
|
112
112
|
Dir.children(base).sort.filter_map do |name|
|
|
@@ -131,6 +131,29 @@ module Tebako
|
|
|
131
131
|
|
|
132
132
|
private
|
|
133
133
|
|
|
134
|
+
# ---- extension points for BootstrapManager (tebako-bootstrap release
|
|
135
|
+
# resolution); overridden there, everything else is shared machinery ----
|
|
136
|
+
|
|
137
|
+
def default_mirror
|
|
138
|
+
DEFAULT_MIRROR
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def mirror_env_var
|
|
142
|
+
"TEBAKO_RUNTIME_MIRROR"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def index_files
|
|
146
|
+
INDEX_FILES
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def cache_subdir
|
|
150
|
+
RUNTIMES_DIR
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def release_name
|
|
154
|
+
"tebako-runtime-ruby"
|
|
155
|
+
end
|
|
156
|
+
|
|
134
157
|
def install(executable, ruby_version, platform, tebako_version)
|
|
135
158
|
ref = runtime_ref(ruby_version, platform, tebako_version)
|
|
136
159
|
offline_check(ref, tebako_version)
|
|
@@ -146,7 +169,7 @@ module Tebako
|
|
|
146
169
|
|
|
147
170
|
Tebako.packaging_error(123, "#{ref} is not cached and downloads are disabled " \
|
|
148
171
|
"(release index: #{index_urls(tebako_version).join(", ")}; " \
|
|
149
|
-
"
|
|
172
|
+
"#{mirror_env_var}=#{@mirror})")
|
|
150
173
|
end
|
|
151
174
|
|
|
152
175
|
def find_entry(index, ruby_version, platform, tebako_version)
|
|
@@ -178,14 +201,14 @@ module Tebako
|
|
|
178
201
|
|
|
179
202
|
def fetch_index(tebako_version)
|
|
180
203
|
tried = []
|
|
181
|
-
|
|
204
|
+
index_files.each do |name|
|
|
182
205
|
return parse_index(name, fetch_text(index_url(name, tebako_version)), tebako_version)
|
|
183
206
|
rescue IndexUnavailable
|
|
184
207
|
tried << index_url(name, tebako_version)
|
|
185
208
|
rescue DownloadFailed => e
|
|
186
209
|
Tebako.packaging_error(122, e.message)
|
|
187
210
|
end
|
|
188
|
-
Tebako.packaging_error(124, "
|
|
211
|
+
Tebako.packaging_error(124, "#{release_name} release v#{tebako_version} provides no usable package " \
|
|
189
212
|
"index (tried: #{tried.join(", ")})")
|
|
190
213
|
end
|
|
191
214
|
|
|
@@ -333,7 +356,7 @@ module Tebako
|
|
|
333
356
|
end
|
|
334
357
|
|
|
335
358
|
def index_urls(tebako_version)
|
|
336
|
-
|
|
359
|
+
index_files.map { |name| index_url(name, tebako_version) }
|
|
337
360
|
end
|
|
338
361
|
|
|
339
362
|
def package_url(filename, tebako_version)
|
data/lib/tebako/stitcher.rb
CHANGED
|
@@ -75,7 +75,10 @@ module Tebako
|
|
|
75
75
|
FORMAT_DWARFS = 1
|
|
76
76
|
FORMAT_SQUASHFS = 2
|
|
77
77
|
FORMAT_ZIP = 3
|
|
78
|
-
|
|
78
|
+
# Runtime payload slot of a fat package: installed into the shared cache
|
|
79
|
+
# by the bootstrap at first run, never mounted (tpkg.h TPKG_FORMAT_RUNTIME)
|
|
80
|
+
FORMAT_RUNTIME = 4
|
|
81
|
+
FORMAT_IDS = (FORMAT_AUTO..FORMAT_RUNTIME).freeze
|
|
79
82
|
|
|
80
83
|
# Header field offsets
|
|
81
84
|
OFF_PACKAGE_FLAGS = 14
|
|
@@ -89,17 +92,21 @@ module Tebako
|
|
|
89
92
|
# copy of the runtime at +runtime_path+, writing +output+.
|
|
90
93
|
# lean: true marks the package LEAN and records runtime_ref
|
|
91
94
|
# ("ruby@<ruby_version>;tebako=<tebako_version>"); classic packages
|
|
92
|
-
# carry an empty runtime_ref.
|
|
95
|
+
# carry an empty runtime_ref. runtime_sha256 appends ";sha256=<hex>" to
|
|
96
|
+
# the runtime_ref — the checksum the bootstrap verifies a fat package's
|
|
97
|
+
# runtime payload slot against before installing it into the cache.
|
|
93
98
|
def stitch(runtime_path, images:, output:, lean: false, ruby_version: nil, # rubocop:disable Metrics/ParameterLists
|
|
94
|
-
tebako_version: Tebako::VERSION, launcher_abi: 0)
|
|
99
|
+
tebako_version: Tebako::VERSION, launcher_abi: 0, runtime_sha256: nil)
|
|
95
100
|
images = normalize_images(images)
|
|
96
101
|
validate_inputs!(runtime_path, images, lean, ruby_version)
|
|
102
|
+
validate_runtime_sha256!(runtime_sha256)
|
|
97
103
|
|
|
98
104
|
FileUtils.mkdir_p(File.dirname(output))
|
|
99
105
|
FileUtils.cp(runtime_path, output)
|
|
100
106
|
FileUtils.chmod(0o755, output)
|
|
101
107
|
|
|
102
|
-
append(images, output, package_flags(lean), runtime_ref(lean, ruby_version, tebako_version
|
|
108
|
+
append(images, output, package_flags(lean), runtime_ref(lean, ruby_version, tebako_version, runtime_sha256),
|
|
109
|
+
launcher_abi)
|
|
103
110
|
resign_if_needed(output)
|
|
104
111
|
output
|
|
105
112
|
end
|
|
@@ -157,6 +164,8 @@ module Tebako
|
|
|
157
164
|
seen = {}
|
|
158
165
|
images.each do |image|
|
|
159
166
|
validate_image!(image)
|
|
167
|
+
next if image[:format_id] == FORMAT_RUNTIME # payload slots are never mounted
|
|
168
|
+
|
|
160
169
|
mount = image[:mount_point]
|
|
161
170
|
Tebako.packaging_error(126, "duplicate mount point '#{mount}'") if seen[mount]
|
|
162
171
|
|
|
@@ -166,7 +175,7 @@ module Tebako
|
|
|
166
175
|
|
|
167
176
|
def validate_image!(image)
|
|
168
177
|
unless FORMAT_IDS.cover?(image[:format_id])
|
|
169
|
-
Tebako.packaging_error(126, "invalid format_id #{image[:format_id]} (0..
|
|
178
|
+
Tebako.packaging_error(126, "invalid format_id #{image[:format_id]} (0..4 expected)")
|
|
170
179
|
end
|
|
171
180
|
return unless image[:mount_point].bytesize >= MOUNT_POINT_LEN
|
|
172
181
|
|
|
@@ -174,14 +183,21 @@ module Tebako
|
|
|
174
183
|
"mount point '#{image[:mount_point][0, 32]}...' exceeds #{MOUNT_POINT_LEN - 1} bytes")
|
|
175
184
|
end
|
|
176
185
|
|
|
186
|
+
def validate_runtime_sha256!(runtime_sha256)
|
|
187
|
+
return if runtime_sha256.nil? || runtime_sha256.match?(/\A[0-9a-f]{64}\z/)
|
|
188
|
+
|
|
189
|
+
Tebako.packaging_error(126, "runtime_sha256 must be 64 lowercase hex characters")
|
|
190
|
+
end
|
|
191
|
+
|
|
177
192
|
def package_flags(lean)
|
|
178
193
|
lean ? FLAG_LEAN : 0
|
|
179
194
|
end
|
|
180
195
|
|
|
181
|
-
def runtime_ref(lean, ruby_version, tebako_version)
|
|
196
|
+
def runtime_ref(lean, ruby_version, tebako_version, runtime_sha256)
|
|
182
197
|
return "" unless lean
|
|
183
198
|
|
|
184
199
|
ref = "ruby@#{ruby_version};tebako=#{tebako_version}"
|
|
200
|
+
ref += ";sha256=#{runtime_sha256}" if runtime_sha256
|
|
185
201
|
if ref.bytesize >= RUNTIME_REF_LEN
|
|
186
202
|
Tebako.packaging_error(126, "runtime_ref '#{ref}' exceeds #{RUNTIME_REF_LEN - 1} bytes")
|
|
187
203
|
end
|
data/lib/tebako/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.15.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -212,6 +212,7 @@ files:
|
|
|
212
212
|
- include/tebako/tebako-prism.h
|
|
213
213
|
- include/tebako/tpkg.h
|
|
214
214
|
- lib/tebako.rb
|
|
215
|
+
- lib/tebako/bootstrap_manager.rb
|
|
215
216
|
- lib/tebako/build_helpers.rb
|
|
216
217
|
- lib/tebako/cache_manager.rb
|
|
217
218
|
- lib/tebako/cli.rb
|