rbe-tebako 0.15.0
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 +7 -0
- data/.clang-format +4 -0
- data/Brewfile +23 -0
- data/CMakeLists.txt +464 -0
- data/CODE_OF_CONDUCT.adoc +128 -0
- data/CONTRIBUTING.adoc +294 -0
- data/Gemfile +31 -0
- data/INSTALLATION.adoc +233 -0
- data/LICENSE.md +33 -0
- data/README.adoc +1363 -0
- data/Rakefile +35 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/cmake/copy_dir.cmake +29 -0
- data/common.env +5 -0
- data/exe/rbe-tebako +32 -0
- data/exe/rbe-tebako-packager +77 -0
- data/include/tebako/tebako-fs.h +43 -0
- data/include/tebako/tebako-main.h +42 -0
- data/include/tebako/tebako-prism.h +51 -0
- data/lib/rbe-tebako.rb +6 -0
- data/lib/tebako/build_helpers.rb +77 -0
- data/lib/tebako/cache_manager.rb +112 -0
- data/lib/tebako/cli.rb +220 -0
- data/lib/tebako/cli_helpers.rb +165 -0
- data/lib/tebako/codegen.rb +252 -0
- data/lib/tebako/deploy_helper.rb +258 -0
- data/lib/tebako/error.rb +70 -0
- data/lib/tebako/options_manager.rb +338 -0
- data/lib/tebako/package_descriptor.rb +143 -0
- data/lib/tebako/packager/pass1_patch.rb +266 -0
- data/lib/tebako/packager/pass1a_patch.rb +55 -0
- data/lib/tebako/packager/pass2_patch.rb +140 -0
- data/lib/tebako/packager/pass2_patch_crt.rb +46 -0
- data/lib/tebako/packager/pass2msys_patch.rb +190 -0
- data/lib/tebako/packager/patch.rb +54 -0
- data/lib/tebako/packager/patch_buildsystem.rb +124 -0
- data/lib/tebako/packager/patch_helpers.rb +109 -0
- data/lib/tebako/packager/patch_libraries.rb +188 -0
- data/lib/tebako/packager/patch_literals.rb +275 -0
- data/lib/tebako/packager/patch_main.rb +93 -0
- data/lib/tebako/packager/rubygems_patch.rb +83 -0
- data/lib/tebako/packager.rb +210 -0
- data/lib/tebako/packager_lite.rb +78 -0
- data/lib/tebako/ruby_builder.rb +71 -0
- data/lib/tebako/ruby_version.rb +206 -0
- data/lib/tebako/scenario_manager.rb +251 -0
- data/lib/tebako/stripper.rb +135 -0
- data/lib/tebako/version.rb +30 -0
- data/lib/tebako.rb +34 -0
- data/src/tebako-main.cpp +168 -0
- data/tools/.gitattributes +4 -0
- data/tools/.github/workflows/build-containers.yml +190 -0
- data/tools/.github/workflows/lint.yml +41 -0
- data/tools/.github/workflows/test.yml +331 -0
- data/tools/.gitignore +1 -0
- data/tools/README.md +49 -0
- data/tools/ci-scripts/arm-brew-install.sh +43 -0
- data/tools/ci-scripts/arm-brew-setup.sh +33 -0
- data/tools/ci-scripts/level-up.sh +35 -0
- data/tools/ci-scripts/patch-fbthrift.sh +94 -0
- data/tools/ci-scripts/patch-folly.sh +551 -0
- data/tools/ci-scripts/patch-glog.sh +57 -0
- data/tools/ci-scripts/patch-zstd.sh +57 -0
- data/tools/ci-scripts/tools.sh +63 -0
- data/tools/ci-scripts/x86-brew-install.sh +43 -0
- data/tools/ci-scripts/x86-brew-setup.sh +33 -0
- data/tools/cmake-scripts/def-external-project.cmake +96 -0
- data/tools/cmake-scripts/macos-environment.cmake +91 -0
- data/tools/cmake-scripts/msys-environment.cmake +78 -0
- data/tools/cmake-scripts/setup-libarchive.cmake +93 -0
- data/tools/cmake-scripts/setup-libfmt.cmake +61 -0
- data/tools/cmake-scripts/setup-libhowardhinnerdate.cmake +55 -0
- data/tools/cmake-scripts/setup-libutfcpp.cmake +56 -0
- data/tools/cmake-scripts/version.cmake +162 -0
- data/tools/docker/alpine-3.17-dev.Dockerfile +49 -0
- data/tools/docker/tools/tools.sh +66 -0
- data/tools/docker/ubuntu-20.04-dev.Dockerfile +51 -0
- data/tools/dwarfs-test-helper/CMakeLists.txt +34 -0
- data/tools/include/pro-statvfs.h +57 -0
- data/tools/tests/cmake/CMakeLists.txt +81 -0
- data/tools/tests/setup-libfmt/CMakeLists.txt +35 -0
- data/tools/tests/setup-libhowardhinnerdate/CMakeLists.txt +35 -0
- data/tools/tests/setup-librachive/CMakeLists.txt +35 -0
- data/tools/tests/setup-libutfcpp/CMakeLists.txt +36 -0
- data/tools/tests/setup-openssl/CMakeLists.txt +36 -0
- metadata +312 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024-2025 [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 "bundler"
|
|
29
|
+
require "fileutils"
|
|
30
|
+
require "find"
|
|
31
|
+
|
|
32
|
+
require_relative "error"
|
|
33
|
+
require_relative "build_helpers"
|
|
34
|
+
require_relative "packager/patch_helpers"
|
|
35
|
+
require_relative "scenario_manager"
|
|
36
|
+
|
|
37
|
+
require_relative "packager/patch"
|
|
38
|
+
require_relative "packager/rubygems_patch"
|
|
39
|
+
|
|
40
|
+
# Tebako - an executable packager
|
|
41
|
+
module Tebako
|
|
42
|
+
# Tebako packaging support (deployer)
|
|
43
|
+
class DeployHelper < ScenarioManagerWithBundler # rubocop:disable Metrics/ClassLength
|
|
44
|
+
def initialize(fs_root, fs_entrance, target_dir, pre_dir)
|
|
45
|
+
super(fs_root, fs_entrance)
|
|
46
|
+
@fs_root = fs_root
|
|
47
|
+
@fs_entrance = fs_entrance
|
|
48
|
+
@target_dir = target_dir
|
|
49
|
+
@pre_dir = pre_dir
|
|
50
|
+
@verbose = %w[yes true].include?(ENV.fetch("VERBOSE", nil))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
attr_reader :gem_home
|
|
54
|
+
|
|
55
|
+
def configure(ruby_ver, cwd)
|
|
56
|
+
@ruby_ver = ruby_ver
|
|
57
|
+
@needs_bundler = true unless @ruby_ver.ruby31?
|
|
58
|
+
@cwd = cwd
|
|
59
|
+
|
|
60
|
+
@tbd = File.join(@target_dir, "bin")
|
|
61
|
+
@tgd = @gem_home = File.join(@target_dir, "lib", "ruby", "gems", @ruby_ver.api_version)
|
|
62
|
+
@tld = File.join(@target_dir, "local")
|
|
63
|
+
|
|
64
|
+
configure_scenario
|
|
65
|
+
configure_commands
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def deploy
|
|
69
|
+
BuildHelpers.with_env(deploy_env) do
|
|
70
|
+
update_rubygems
|
|
71
|
+
system("#{@gem_command} env") if @verbose
|
|
72
|
+
install_gem("tebako-runtime")
|
|
73
|
+
install_gem("bundler", @bundler_version) if @needs_bundler
|
|
74
|
+
deploy_solution
|
|
75
|
+
check_cwd
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def deploy_env
|
|
80
|
+
{
|
|
81
|
+
"GEM_HOME" => gem_home,
|
|
82
|
+
"GEM_PATH" => gem_home,
|
|
83
|
+
"GEM_SPEC_CACHE" => File.join(@target_dir, "spec_cache"),
|
|
84
|
+
"TEBAKO_PASS_THROUGH" => "1"
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def install_gem(name, ver = nil)
|
|
89
|
+
puts " ... installing #{name} gem#{" version #{ver}" if ver}"
|
|
90
|
+
|
|
91
|
+
params = [@gem_command, "install", name.to_s]
|
|
92
|
+
params += ["-v", ver.to_s] if ver
|
|
93
|
+
params += ["--no-document", "--install-dir", @tgd, "--bindir", @tbd]
|
|
94
|
+
params += ["--platform", "ruby"] if msys?
|
|
95
|
+
BuildHelpers.run_with_capture_v(params)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def update_rubygems
|
|
99
|
+
return if @ruby_ver.ruby31?
|
|
100
|
+
|
|
101
|
+
puts " ... updating rubygems to #{Tebako::RUBYGEMS_VERSION}"
|
|
102
|
+
BuildHelpers.run_with_capture_v([@gem_command, "update", "--no-doc", "--system",
|
|
103
|
+
Tebako::RUBYGEMS_VERSION])
|
|
104
|
+
|
|
105
|
+
patch = Packager::RubygemsUpdatePatch.new(@fs_mount_point).patch_map
|
|
106
|
+
Packager.do_patch(patch, "#{@target_dir}/lib/ruby/site_ruby/#{@ruby_ver.api_version}")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def bundle_config
|
|
112
|
+
bundle_config_option(["build.ffi", "--disable-system-libffi"])
|
|
113
|
+
bundle_config_option(["build.nokogiri", @nokogiri_option])
|
|
114
|
+
bundle_config_option(["force_ruby_platform", @force_ruby_platform])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def bundle_config_option(opt)
|
|
118
|
+
BuildHelpers.run_with_capture_v([@bundler_command, bundler_reference, "config", "set", "--local"] + opt)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def check_entry_point(entry_point_root)
|
|
122
|
+
fs_entry_point = File.join(entry_point_root, @fs_entrance)
|
|
123
|
+
puts " ... target entry point will be at #{File.join(@fs_mount_point, fs_entry_point)}"
|
|
124
|
+
|
|
125
|
+
return if File.exist?(File.join(@target_dir, fs_entry_point))
|
|
126
|
+
|
|
127
|
+
raise Tebako::Error.new("Entry point #{fs_entry_point} does not exist or is not accessible", 106)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def check_cwd
|
|
131
|
+
return if @cwd.nil?
|
|
132
|
+
|
|
133
|
+
cwd_full = File.join(@target_dir, @cwd)
|
|
134
|
+
return if File.directory?(cwd_full)
|
|
135
|
+
|
|
136
|
+
raise Tebako::Error.new("Package working directory #{@cwd} does not exist", 108)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def collect_and_deploy_gem(gemspec)
|
|
140
|
+
puts " ... collecting gem from gemspec #{gemspec}"
|
|
141
|
+
|
|
142
|
+
copy_files(@pre_dir)
|
|
143
|
+
|
|
144
|
+
Dir.chdir(@pre_dir) do
|
|
145
|
+
# spec = Bundler.load_gemspec(gemspec)
|
|
146
|
+
# puts spec.executables.first unless spec.executables.empty?
|
|
147
|
+
# puts spec.bindir
|
|
148
|
+
|
|
149
|
+
BuildHelpers.run_with_capture_v([@gem_command, "build", gemspec])
|
|
150
|
+
install_all_gems_or_fail
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
check_entry_point("bin")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def collect_and_deploy_gem_and_gemfile(gemspec)
|
|
157
|
+
puts " ... collecting gem from gemspec #{gemspec} and Gemfile"
|
|
158
|
+
|
|
159
|
+
copy_files(@pre_dir)
|
|
160
|
+
|
|
161
|
+
Dir.chdir(@pre_dir) do
|
|
162
|
+
bundle_config
|
|
163
|
+
puts " *** It may take a long time for a big project. It takes REALLY long time on Windows ***"
|
|
164
|
+
BuildHelpers.run_with_capture_v([@bundler_command, bundler_reference, "install", "--jobs=#{ncores}"])
|
|
165
|
+
BuildHelpers.run_with_capture_v([@bundler_command, bundler_reference, "exec", @gem_command, "build", gemspec])
|
|
166
|
+
install_all_gems_or_fail
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
check_entry_point("bin")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def configure_commands
|
|
173
|
+
if msys?
|
|
174
|
+
configure_commands_msys
|
|
175
|
+
else
|
|
176
|
+
configure_commands_not_msys
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
@gem_command = File.join(@tbd, "gem#{@cmd_suffix}")
|
|
180
|
+
@bundler_command = File.join(@tbd, "bundle#{@bat_suffix}")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def configure_commands_msys
|
|
184
|
+
@cmd_suffix = ".cmd"
|
|
185
|
+
@bat_suffix = ".bat"
|
|
186
|
+
@force_ruby_platform = "true"
|
|
187
|
+
@nokogiri_option = "--use-system-libraries"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def configure_commands_not_msys
|
|
191
|
+
@cmd_suffix = ""
|
|
192
|
+
@bat_suffix = ""
|
|
193
|
+
@force_ruby_platform = "false"
|
|
194
|
+
@nokogiri_option = "--no-use-system-libraries"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def copy_files(dest)
|
|
198
|
+
FileUtils.mkdir_p(dest)
|
|
199
|
+
if Dir.exist?(@fs_root) && File.readable?(@fs_root)
|
|
200
|
+
begin
|
|
201
|
+
FileUtils.cp_r(File.join(@fs_root, "."), dest)
|
|
202
|
+
rescue StandardError
|
|
203
|
+
raise Tebako::Error.new("#{@fs_root} does not exist or is not accessible.", 107)
|
|
204
|
+
end
|
|
205
|
+
return
|
|
206
|
+
end
|
|
207
|
+
raise Tebako::Error.new("#{@fs_root} is not accessible or is not a directory.", 107)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def deploy_gem(gem)
|
|
211
|
+
puts " ... installing Ruby gem from #{gem}"
|
|
212
|
+
copy_files(@pre_dir)
|
|
213
|
+
Dir.chdir(@pre_dir) { install_gem(gem) }
|
|
214
|
+
check_entry_point("bin")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def deploy_gemfile
|
|
218
|
+
puts " ... deploying Gemfile"
|
|
219
|
+
copy_files(@tld)
|
|
220
|
+
|
|
221
|
+
Dir.chdir(@tld) do
|
|
222
|
+
bundle_config
|
|
223
|
+
puts " *** It may take a long time for a big project. It takes REALLY long time on Windows ***"
|
|
224
|
+
BuildHelpers.run_with_capture_v([@bundler_command, bundler_reference, "install", "--jobs=#{ncores}"])
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
check_entry_point("local")
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def deploy_simple_script
|
|
231
|
+
puts " ... collecting simple Ruby script from #{@fs_root}"
|
|
232
|
+
copy_files(@tld)
|
|
233
|
+
check_entry_point("local")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def deploy_solution # rubocop:disable Metrics/MethodLength
|
|
237
|
+
case @scenario
|
|
238
|
+
when :simple_script
|
|
239
|
+
deploy_simple_script
|
|
240
|
+
when :gem
|
|
241
|
+
deploy_gem(Dir.glob(File.join(@fs_root, "*.gem")).first)
|
|
242
|
+
when :gemfile
|
|
243
|
+
deploy_gemfile
|
|
244
|
+
when :gemspec
|
|
245
|
+
collect_and_deploy_gem(Dir.glob(File.join(@fs_root, "*.gemspec")).first)
|
|
246
|
+
when :gemspec_and_gemfile
|
|
247
|
+
collect_and_deploy_gem_and_gemfile(Dir.glob(File.join(@fs_root, "*.gemspec")).first)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def install_all_gems_or_fail
|
|
252
|
+
gem_files = Dir.glob("*.gem").map { |file| File.expand_path(file) }
|
|
253
|
+
raise Tebako::Error, "No gem files found after build" if gem_files.empty?
|
|
254
|
+
|
|
255
|
+
gem_files.each { |gem_file| install_gem(gem_file) }
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
data/lib/tebako/error.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2023-2025 [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
|
+
# Tebako - an executable packager
|
|
29
|
+
module Tebako
|
|
30
|
+
PACKAGING_ERRORS = {
|
|
31
|
+
101 => "'tebako setup' configure step failed",
|
|
32
|
+
102 => "'tebako setup' build step failed",
|
|
33
|
+
103 => "'tebako press' configure step failed",
|
|
34
|
+
104 => "'tebako press' build step failed",
|
|
35
|
+
105 => "Failed to map MSys path to Windows",
|
|
36
|
+
106 => "Entry point does not exist or is not accessible",
|
|
37
|
+
107 => "Project root does not exist or is not accessible",
|
|
38
|
+
108 => "Package working directory does not exist",
|
|
39
|
+
109 => "Invalid Ruby version format",
|
|
40
|
+
110 => "Ruby version is not supported",
|
|
41
|
+
111 => "Ruby version is not supported on Windows",
|
|
42
|
+
112 => "OS is not supported",
|
|
43
|
+
113 => "Path to root shall be absolute. Relative path is not allowed",
|
|
44
|
+
114 => "Entry point is not within the project root",
|
|
45
|
+
115 => "Failed to load Gemfile",
|
|
46
|
+
116 => "Ruby version does not satify Gemfile requirements",
|
|
47
|
+
117 => "Failed to load Gemfile.lock",
|
|
48
|
+
118 => "Bundler version in Gemfile.lock does satisfy minimal Tebako version requirememnts",
|
|
49
|
+
119 => "Failed to find compatible bundler version",
|
|
50
|
+
201 => "Warning. Could not create cache version file"
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
def packaging_error(code, extm = nil)
|
|
55
|
+
msg = PACKAGING_ERRORS[code]
|
|
56
|
+
msg += ": #{extm}" unless extm.nil?
|
|
57
|
+
msg = "Unknown packaging error" if msg.nil?
|
|
58
|
+
raise Tebako::Error.new msg, code
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Tebako error class
|
|
63
|
+
class Error < StandardError
|
|
64
|
+
def initialize(msg = "Unspecified error", code = 255)
|
|
65
|
+
@error_code = code
|
|
66
|
+
super(msg)
|
|
67
|
+
end
|
|
68
|
+
attr_accessor :error_code
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2023-2025 [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 "etc"
|
|
29
|
+
require "fileutils"
|
|
30
|
+
require "pathname"
|
|
31
|
+
require "rbconfig"
|
|
32
|
+
|
|
33
|
+
require_relative "codegen"
|
|
34
|
+
require_relative "error"
|
|
35
|
+
require_relative "ruby_version"
|
|
36
|
+
require_relative "version"
|
|
37
|
+
|
|
38
|
+
# Tebako - an executable packager
|
|
39
|
+
# Command-line interface methods
|
|
40
|
+
module Tebako
|
|
41
|
+
# Cli helpers
|
|
42
|
+
class OptionsManager # rubocop:disable Metrics/ClassLength
|
|
43
|
+
def initialize(options)
|
|
44
|
+
@options = options
|
|
45
|
+
@rv = Tebako::RubyVersion.new(@options["Ruby"])
|
|
46
|
+
@ruby_ver, @ruby_hash = @rv.extend_ruby_version
|
|
47
|
+
@scmb = ScenarioManagerBase.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
attr_reader :ruby_ver, :rv
|
|
51
|
+
|
|
52
|
+
def cfg_options
|
|
53
|
+
## {v_parts[3]} may be something like rc1 that won't work with CMake
|
|
54
|
+
v_parts = Tebako::VERSION.split(".")
|
|
55
|
+
# Cannot use 'xxx' as parameters because it does not work in Windows shells
|
|
56
|
+
# So we have to use \"xxx\"
|
|
57
|
+
@cfg_options ||=
|
|
58
|
+
"-DCMAKE_BUILD_TYPE=Release -DRUBY_VER:STRING=\"#{@ruby_ver}\" -DRUBY_HASH:STRING=\"#{@ruby_hash}\" " \
|
|
59
|
+
"-DDEPS:STRING=\"#{deps}\" -G \"#{@scmb.m_files}\" -B \"#{output_folder}\" -S \"#{source}\" " \
|
|
60
|
+
"#{remove_glibc_private} -DTEBAKO_VERSION:STRING=\"#{v_parts[0]}.#{v_parts[1]}.#{v_parts[2]}\""
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def cwd
|
|
64
|
+
f_cwd = @options["cwd"]&.gsub("\\", "/")
|
|
65
|
+
@cwd ||= f_cwd
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def cwd_announce
|
|
69
|
+
@cwd_announce ||= cwd.nil? ? "<Host current directory>" : cwd
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# DATA_BIN_DIR folder is used to create packaged filesystem
|
|
73
|
+
# set(DATA_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/p)
|
|
74
|
+
def data_bin_dir
|
|
75
|
+
@data_bin_dir ||= File.join(output_folder, "p")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Mode File(s) Content
|
|
79
|
+
# bundle fs.bin Application
|
|
80
|
+
# both fs.bin, fs2.bin Stub, application respectively
|
|
81
|
+
# runtime fs.bin Stub
|
|
82
|
+
# app fs2.bin Application
|
|
83
|
+
|
|
84
|
+
def data_bundle_file
|
|
85
|
+
@data_bundle_file ||= File.join(data_bin_dir, "fs.bin")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def data_stub_file
|
|
89
|
+
@data_stub_file ||= File.join(data_bin_dir, "fs.bin")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def data_app_file
|
|
93
|
+
@data_app_file ||= File.join(data_bin_dir, "fs2.bin")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# DATA_PRE_DIR folder is used to build gems that need to be packaged
|
|
97
|
+
# set(DATA_PRE_DIR ${CMAKE_CURRENT_BINARY_DIR}/r)
|
|
98
|
+
def data_pre_dir
|
|
99
|
+
@data_pre_dir ||= File.join(output_folder, "r")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# DATA_SRC_DIR folder is used to collect all files that need to be packaged
|
|
103
|
+
# set(DATA_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/s)
|
|
104
|
+
def data_src_dir
|
|
105
|
+
@data_src_dir ||= File.join(output_folder, "s")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def deps
|
|
109
|
+
@deps ||= File.join(prefix, "deps")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def deps_bin_dir
|
|
113
|
+
@deps_bin_dir ||= File.join(deps, "bin")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def deps_lib_dir
|
|
117
|
+
@deps_lib_dir ||= File.join(deps, "lib")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def folder_within_root?(folder)
|
|
121
|
+
folder_path = Pathname.new(folder.chomp("/"))
|
|
122
|
+
root_path = Pathname.new(root.chomp("/"))
|
|
123
|
+
folder_path.ascend do |path|
|
|
124
|
+
return true if path == root_path
|
|
125
|
+
end
|
|
126
|
+
false
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def fs_current
|
|
130
|
+
fs_current = Dir.pwd
|
|
131
|
+
if @scmb.msys?
|
|
132
|
+
fs_current, cygpath_res = Open3.capture2e("cygpath", "-w", fs_current)
|
|
133
|
+
Tebako.packaging_error(101) unless cygpath_res.success?
|
|
134
|
+
fs_current.strip!
|
|
135
|
+
end
|
|
136
|
+
@fs_current ||= fs_current&.gsub("\\", "/")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def fs_entrance
|
|
140
|
+
@fs_entrance ||= @options["entry-point"]&.gsub("\\", "/")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def handle_nil_prefix
|
|
144
|
+
env_prefix = ENV.fetch("TEBAKO_PREFIX", nil)
|
|
145
|
+
if env_prefix.nil?
|
|
146
|
+
puts "No prefix specified, using ~/.tebako"
|
|
147
|
+
File.expand_path("~/.tebako")
|
|
148
|
+
else
|
|
149
|
+
puts "Using TEBAKO_PREFIX environment variable as prefix"
|
|
150
|
+
File.expand_path(env_prefix.gsub("\\", "/"))
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def l_level
|
|
155
|
+
@l_level ||= @options["log-level"].nil? ? "error" : @options["log-level"]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def mode
|
|
159
|
+
@mode ||= @options["mode"].nil? ? "bundle" : @options["mode"]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def output_folder
|
|
163
|
+
@output_folder ||= File.join(prefix, "o")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def output_type_first
|
|
167
|
+
@output_type_first ||= %w[both runtime].include?(mode) ? "runtime package" : "package"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def output_type_second
|
|
171
|
+
"application package"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def package
|
|
175
|
+
package = if @options["output"].nil?
|
|
176
|
+
File.join(Dir.pwd, mode == "runtime" ? "tebako-runtime" : File.basename(fs_entrance, ".*"))
|
|
177
|
+
else
|
|
178
|
+
@options["output"]&.gsub("\\", "/")
|
|
179
|
+
end
|
|
180
|
+
@package ||= if relative?(package)
|
|
181
|
+
File.join(fs_current, package)
|
|
182
|
+
else
|
|
183
|
+
package
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def package_within_root?
|
|
188
|
+
folder_within_root?(package)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def patchelf?
|
|
192
|
+
@options["patchelf"]
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def prefix
|
|
196
|
+
@prefix ||= if @options["prefix"].nil?
|
|
197
|
+
handle_nil_prefix
|
|
198
|
+
elsif @options["prefix"] == "PWD"
|
|
199
|
+
Dir.pwd
|
|
200
|
+
else
|
|
201
|
+
File.expand_path(@options["prefix"]&.gsub("\\", "/"))
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def prefix_within_root?
|
|
206
|
+
folder_within_root?(prefix)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def press_announce(is_msys)
|
|
210
|
+
case mode
|
|
211
|
+
when "application"
|
|
212
|
+
press_announce_application(is_msys)
|
|
213
|
+
when "both"
|
|
214
|
+
press_announce_both
|
|
215
|
+
when "bundle"
|
|
216
|
+
press_announce_bundle
|
|
217
|
+
when "runtime"
|
|
218
|
+
press_announce_runtime
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def press_announce_ref(is_msys)
|
|
223
|
+
if is_msys
|
|
224
|
+
" referencing runtime at '#{ref}'"
|
|
225
|
+
else
|
|
226
|
+
""
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def press_announce_application(is_msys)
|
|
231
|
+
<<~ANN
|
|
232
|
+
Running tebako press at #{prefix}
|
|
233
|
+
Mode: 'application'
|
|
234
|
+
Ruby version: '#{@ruby_ver}'
|
|
235
|
+
Project root: '#{root}'
|
|
236
|
+
Application entry point: '#{fs_entrance}'
|
|
237
|
+
Package file name: '#{package}.tebako'#{press_announce_ref(is_msys)}
|
|
238
|
+
Package working directory: '#{cwd_announce}'
|
|
239
|
+
ANN
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def press_announce_both
|
|
243
|
+
<<~ANN
|
|
244
|
+
Running tebako press at #{prefix}
|
|
245
|
+
Mode: 'both'
|
|
246
|
+
Ruby version: '#{@ruby_ver}'
|
|
247
|
+
Project root: '#{root}'
|
|
248
|
+
Application entry point: '#{fs_entrance}'
|
|
249
|
+
Runtime file name: '#{package}'
|
|
250
|
+
Package file name: '#{package}.tebako'
|
|
251
|
+
Loging level: '#{l_level}'
|
|
252
|
+
Package working directory: '#{cwd_announce}'
|
|
253
|
+
ANN
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def press_announce_bundle
|
|
257
|
+
<<~ANN
|
|
258
|
+
Running tebako press at #{prefix}
|
|
259
|
+
Mode: 'bundle'
|
|
260
|
+
Ruby version: '#{@ruby_ver}'
|
|
261
|
+
Project root: '#{root}'
|
|
262
|
+
Application entry point: '#{fs_entrance}'
|
|
263
|
+
Package file name: '#{package}'
|
|
264
|
+
Loging level: '#{l_level}'
|
|
265
|
+
Package working directory: '#{cwd_announce}'
|
|
266
|
+
ANN
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def press_announce_runtime
|
|
270
|
+
<<~ANN
|
|
271
|
+
Running tebako press at #{prefix}
|
|
272
|
+
Mode: 'runtime'
|
|
273
|
+
Ruby version: '#{@ruby_ver}'
|
|
274
|
+
Runtime file name: '#{package}'
|
|
275
|
+
Loging level: '#{l_level}'
|
|
276
|
+
ANN
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def press_options
|
|
280
|
+
@press_options ||= "-DPCKG:STRING='#{package}' -DLOG_LEVEL:STRING='#{l_level}' " \
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def process_gemfile(gemfile_path)
|
|
284
|
+
folder = File.dirname(gemfile_path)
|
|
285
|
+
filename = File.basename(gemfile_path)
|
|
286
|
+
# Change directory to the folder containing the Gemfile
|
|
287
|
+
# Because Bundler::Definition.build *sometimes* requires to be in
|
|
288
|
+
# the Gemfile directory
|
|
289
|
+
Dir.chdir(folder) do
|
|
290
|
+
@rv = Tebako::RubyVersionWithGemfile.new(@options["Ruby"], filename)
|
|
291
|
+
end
|
|
292
|
+
@ruby_ver, @ruby_hash = @rv.extend_ruby_version
|
|
293
|
+
@ruby_src_dir = nil
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def relative?(path)
|
|
297
|
+
Pathname.new(path).relative?
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def ref
|
|
301
|
+
@ref ||= @options["ref"].nil? ? "tebako-runtime" : @options["ref"].gsub("\\", "/")
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def remove_glibc_private
|
|
305
|
+
@remove_glibc_private ||= if RUBY_PLATFORM.end_with?("linux") || RUBY_PLATFORM.end_with?("linux-gnu")
|
|
306
|
+
"-DREMOVE_GLIBC_PRIVATE=#{@options["patchelf"] ? "ON" : "OFF"}"
|
|
307
|
+
else
|
|
308
|
+
""
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def root
|
|
313
|
+
f_root = @options["root"].nil? ? "" : @options["root"].gsub("\\", "/")
|
|
314
|
+
@root ||= if relative?(f_root)
|
|
315
|
+
File.join(fs_current, f_root)
|
|
316
|
+
else
|
|
317
|
+
File.join(f_root, "")
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def ruby_src_dir
|
|
322
|
+
@ruby_src_dir ||= File.join(deps, "src", "_ruby_#{@ruby_ver}")
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def source
|
|
326
|
+
c_path = Pathname.new(__FILE__).realpath
|
|
327
|
+
@source ||= File.expand_path("../../..", c_path)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def stash_dir(rver = nil)
|
|
331
|
+
@stash_dir ||= "#{stash_dir_all}_#{rver || @ruby_ver}"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def stash_dir_all
|
|
335
|
+
@stash_dir_all ||= File.join(deps, "stash")
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|