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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +4 -0
  3. data/Brewfile +23 -0
  4. data/CMakeLists.txt +464 -0
  5. data/CODE_OF_CONDUCT.adoc +128 -0
  6. data/CONTRIBUTING.adoc +294 -0
  7. data/Gemfile +31 -0
  8. data/INSTALLATION.adoc +233 -0
  9. data/LICENSE.md +33 -0
  10. data/README.adoc +1363 -0
  11. data/Rakefile +35 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/cmake/copy_dir.cmake +29 -0
  15. data/common.env +5 -0
  16. data/exe/rbe-tebako +32 -0
  17. data/exe/rbe-tebako-packager +77 -0
  18. data/include/tebako/tebako-fs.h +43 -0
  19. data/include/tebako/tebako-main.h +42 -0
  20. data/include/tebako/tebako-prism.h +51 -0
  21. data/lib/rbe-tebako.rb +6 -0
  22. data/lib/tebako/build_helpers.rb +77 -0
  23. data/lib/tebako/cache_manager.rb +112 -0
  24. data/lib/tebako/cli.rb +220 -0
  25. data/lib/tebako/cli_helpers.rb +165 -0
  26. data/lib/tebako/codegen.rb +252 -0
  27. data/lib/tebako/deploy_helper.rb +258 -0
  28. data/lib/tebako/error.rb +70 -0
  29. data/lib/tebako/options_manager.rb +338 -0
  30. data/lib/tebako/package_descriptor.rb +143 -0
  31. data/lib/tebako/packager/pass1_patch.rb +266 -0
  32. data/lib/tebako/packager/pass1a_patch.rb +55 -0
  33. data/lib/tebako/packager/pass2_patch.rb +140 -0
  34. data/lib/tebako/packager/pass2_patch_crt.rb +46 -0
  35. data/lib/tebako/packager/pass2msys_patch.rb +190 -0
  36. data/lib/tebako/packager/patch.rb +54 -0
  37. data/lib/tebako/packager/patch_buildsystem.rb +124 -0
  38. data/lib/tebako/packager/patch_helpers.rb +109 -0
  39. data/lib/tebako/packager/patch_libraries.rb +188 -0
  40. data/lib/tebako/packager/patch_literals.rb +275 -0
  41. data/lib/tebako/packager/patch_main.rb +93 -0
  42. data/lib/tebako/packager/rubygems_patch.rb +83 -0
  43. data/lib/tebako/packager.rb +210 -0
  44. data/lib/tebako/packager_lite.rb +78 -0
  45. data/lib/tebako/ruby_builder.rb +71 -0
  46. data/lib/tebako/ruby_version.rb +206 -0
  47. data/lib/tebako/scenario_manager.rb +251 -0
  48. data/lib/tebako/stripper.rb +135 -0
  49. data/lib/tebako/version.rb +30 -0
  50. data/lib/tebako.rb +34 -0
  51. data/src/tebako-main.cpp +168 -0
  52. data/tools/.gitattributes +4 -0
  53. data/tools/.github/workflows/build-containers.yml +190 -0
  54. data/tools/.github/workflows/lint.yml +41 -0
  55. data/tools/.github/workflows/test.yml +331 -0
  56. data/tools/.gitignore +1 -0
  57. data/tools/README.md +49 -0
  58. data/tools/ci-scripts/arm-brew-install.sh +43 -0
  59. data/tools/ci-scripts/arm-brew-setup.sh +33 -0
  60. data/tools/ci-scripts/level-up.sh +35 -0
  61. data/tools/ci-scripts/patch-fbthrift.sh +94 -0
  62. data/tools/ci-scripts/patch-folly.sh +551 -0
  63. data/tools/ci-scripts/patch-glog.sh +57 -0
  64. data/tools/ci-scripts/patch-zstd.sh +57 -0
  65. data/tools/ci-scripts/tools.sh +63 -0
  66. data/tools/ci-scripts/x86-brew-install.sh +43 -0
  67. data/tools/ci-scripts/x86-brew-setup.sh +33 -0
  68. data/tools/cmake-scripts/def-external-project.cmake +96 -0
  69. data/tools/cmake-scripts/macos-environment.cmake +91 -0
  70. data/tools/cmake-scripts/msys-environment.cmake +78 -0
  71. data/tools/cmake-scripts/setup-libarchive.cmake +93 -0
  72. data/tools/cmake-scripts/setup-libfmt.cmake +61 -0
  73. data/tools/cmake-scripts/setup-libhowardhinnerdate.cmake +55 -0
  74. data/tools/cmake-scripts/setup-libutfcpp.cmake +56 -0
  75. data/tools/cmake-scripts/version.cmake +162 -0
  76. data/tools/docker/alpine-3.17-dev.Dockerfile +49 -0
  77. data/tools/docker/tools/tools.sh +66 -0
  78. data/tools/docker/ubuntu-20.04-dev.Dockerfile +51 -0
  79. data/tools/dwarfs-test-helper/CMakeLists.txt +34 -0
  80. data/tools/include/pro-statvfs.h +57 -0
  81. data/tools/tests/cmake/CMakeLists.txt +81 -0
  82. data/tools/tests/setup-libfmt/CMakeLists.txt +35 -0
  83. data/tools/tests/setup-libhowardhinnerdate/CMakeLists.txt +35 -0
  84. data/tools/tests/setup-librachive/CMakeLists.txt +35 -0
  85. data/tools/tests/setup-libutfcpp/CMakeLists.txt +36 -0
  86. data/tools/tests/setup-openssl/CMakeLists.txt +36 -0
  87. metadata +312 -0
data/lib/tebako/cli.rb ADDED
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Copyright (c) 2021-2025 [Ribose Inc](https://www.ribose.com).
5
+ # All rights reserved.
6
+ # This file is a part of the Tebako project.
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions
10
+ # are met:
11
+ # 1. Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
21
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require "digest"
30
+ require "fileutils"
31
+ require "find"
32
+ require "pathname"
33
+ require "open3"
34
+ require "thor"
35
+ require "yaml"
36
+
37
+ require_relative "cache_manager"
38
+ require_relative "cli_helpers"
39
+ require_relative "error"
40
+ require_relative "ruby_version"
41
+ require_relative "scenario_manager"
42
+ require_relative "version"
43
+
44
+ # Tebako - an executable packager
45
+ # Implementation of tebako command-line interface
46
+ module Tebako
47
+ DEFAULT_TEBAFILE = ".tebako.yml"
48
+ # Tebako packager front-end
49
+ class Cli < Thor # rubocop:disable Metrics/ClassLength
50
+ package_name "Tebako"
51
+ class_option :prefix, type: :string, aliases: "-p", required: false,
52
+ desc: "A path to tebako packaging environment, '~/.tebako' ('$HOME/.tebako') by default"
53
+ class_option :devmode, type: :boolean, aliases: "-D",
54
+ desc: "Developer mode, please do not use if unsure"
55
+ class_option :tebafile, type: :string, aliases: "-t", required: false,
56
+ desc: "tebako configuration file 'tebafile', '$PWD/.tebako.yml' by default"
57
+ desc "clean", "Clean tebako packaging environment"
58
+ def clean
59
+ (om, cm) = bootstrap(clean: true)
60
+ cm.clean_cache
61
+ extra_win_clean([om.deps])
62
+ end
63
+
64
+ desc "clean_ruby", "Clean Ruby source from tebako packaging environment"
65
+ method_option :Ruby, type: :string, aliases: "-R", required: false,
66
+ enum: Tebako::RubyVersion::RUBY_VERSIONS.keys,
67
+ desc: "Ruby version to clean, all available versions by default"
68
+ def clean_ruby
69
+ puts "Cleaning Ruby sources from tebako packaging environment"
70
+ (om,) = bootstrap(clean: true)
71
+
72
+ suffix = options["Ruby"].nil? ? "" : "_#{options["Ruby"]}"
73
+ nmr = Dir.glob(File.join(om.deps, "src", "_ruby#{suffix}*"))
74
+ nms = Dir.glob(File.join(om.deps, "stash#{suffix}*"))
75
+
76
+ FileUtils.rm_rf(nmr + nms, secure: true)
77
+ extra_win_clean(nmr)
78
+ end
79
+
80
+ desc "hash", "Print build script hash (ci cache key)"
81
+ def hash
82
+ print Digest::SHA256.hexdigest [File.read(File.join(source, "CMakeLists.txt")), Tebako::VERSION].join
83
+ end
84
+
85
+ CWD_DESCRIPTION = <<~DESC
86
+ Current working directory for packaged application. This directory shall be specified relative to root.
87
+ #{" " * 65}# If this parameter is not set, the application will start in the current directory of the host file system.
88
+ DESC
89
+
90
+ REF_DESCRIPTION = <<~DESC
91
+ "Referenced tebako run-time package; 'tebako-runtime' by default".
92
+ #{" " * 65}# This option specifies the tebako runtime to be used by the application on Windows and if mode is 'application' only .
93
+ DESC
94
+
95
+ RGP_DESCRIPTION = <<~DESC
96
+ Current working directory for packaged application. This directory shall be specified relative to root.
97
+ #{" " * 65}# If this parameter is not set, the application will start in the current directory of the host file system.
98
+ DESC
99
+
100
+ desc "press", "Press tebako image"
101
+ method_option :cwd, type: :string, aliases: "-c", required: false, desc: CWD_DESCRIPTION
102
+ method_option :"log-level", type: :string, aliases: "-l", required: false, enum: %w[error warn debug trace],
103
+ desc: "Tebako memfs logging level, 'error' by default"
104
+ method_option :output, type: :string, aliases: "-o", required: false,
105
+ desc: "Tebako package file name, entry point base file name in the current folder by default"
106
+ method_option :"entry-point", type: :string, aliases: ["-e", "--entry"], required: false,
107
+ desc: "Ruby application entry point"
108
+ method_option :root, type: :string, aliases: "-r", required: false, desc: "Root folder of the Ruby application"
109
+ method_option :Ruby, type: :string, aliases: "-R", required: false,
110
+ enum: Tebako::RubyVersion::RUBY_VERSIONS.keys,
111
+ desc: "Tebako package Ruby version, #{Tebako::RubyVersion::DEFAULT_RUBY_VERSION} by default"
112
+ method_option :patchelf, aliases: "-P", type: :boolean, desc: RGP_DESCRIPTION
113
+ method_option :mode, type: :string, aliases: "-m", required: false, enum: %w[bundle both runtime application],
114
+ desc: "Tebako press mode, 'bundle' by default"
115
+ method_option :ref, type: :string, aliases: "-u", required: false, desc: REF_DESCRIPTION
116
+
117
+ def press
118
+ validate_press_options
119
+ (om, cm) = bootstrap
120
+
121
+ do_press(om)
122
+ cm.ensure_version_file
123
+ rescue Tebako::Error => e
124
+ puts "Tebako script failed: #{e.message} [#{e.error_code}]"
125
+ exit e.error_code
126
+ end
127
+
128
+ desc "setup", "Set up tebako packaging environment"
129
+ method_option :Ruby, type: :string, aliases: "-R", required: false,
130
+ enum: Tebako::RubyVersion::RUBY_VERSIONS.keys,
131
+ desc: "Tebako package Ruby version, #{Tebako::RubyVersion::DEFAULT_RUBY_VERSION} by default."
132
+ def setup
133
+ (om, cm) = bootstrap
134
+
135
+ do_setup(om)
136
+ cm.ensure_version_file
137
+ rescue Tebako::Error => e
138
+ puts "Tebako script failed: #{e.message} [#{e.error_code}]"
139
+ exit e.error_code
140
+ end
141
+
142
+ def self.exit_on_failure?
143
+ true
144
+ end
145
+
146
+ no_commands do
147
+ def bootstrap(clean: false)
148
+ options_manager = Tebako::OptionsManager.new(options)
149
+ cache_manager = Tebako::CacheManager.new(options_manager.deps, options_manager.source,
150
+ options_manager.output_folder)
151
+ cache_manager.version_cache_check unless options[:devmode] || clean
152
+ [options_manager, cache_manager]
153
+ end
154
+
155
+ # Ruby extension maker sometimes creates files with 'NUL' name on Windows
156
+ # This method removes such files
157
+ def extra_win_clean(nmr)
158
+ return unless nmr.any? && ScenarioManagerBase.new.msys?
159
+
160
+ nmr.each do |path|
161
+ next unless File.directory?(path)
162
+
163
+ extra_win_clean_dir(path)
164
+ end
165
+
166
+ FileUtils.rm_rf(nmr, secure: true)
167
+ end
168
+
169
+ def extra_win_clean_dir(path)
170
+ Find.find(path) do |file_path|
171
+ full_path = "//?/#{file_path}"
172
+ next unless File.file?(full_path) && File.basename(full_path) == "NUL"
173
+
174
+ FileUtils.rm_f(full_path)
175
+ end
176
+ end
177
+ end
178
+
179
+ no_commands do
180
+ def initialize(*args)
181
+ super
182
+ return if args[2][:current_command].name.include?("hash")
183
+
184
+ puts "Tebako executable packager version #{Tebako::VERSION}"
185
+ end
186
+
187
+ def options
188
+ original_options = super
189
+ tebafile = original_options["tebafile"].nil? ? DEFAULT_TEBAFILE : original_options["tebafile"]
190
+ if File.exist?(tebafile)
191
+ Thor::CoreExt::HashWithIndifferentAccess.new(options_from_tebafile(tebafile).merge(original_options))
192
+ else
193
+ puts "Warning: Tebako configuration file '#{tebafile}' not found." unless original_options["tebafile"].nil?
194
+ original_options
195
+ end
196
+ end
197
+
198
+ def source
199
+ c_path = Pathname.new(__FILE__).realpath
200
+ @source ||= File.expand_path("../../..", c_path)
201
+ end
202
+ end
203
+
204
+ no_commands do
205
+ def validate_press_options
206
+ return unless options["mode"] != "runtime"
207
+
208
+ opts = ""
209
+ opts += " '--root'" if options["root"].nil?
210
+ if options["entry-point"].nil?
211
+ opts += ", " unless opts.empty?
212
+ opts += " '--entry-point'"
213
+ end
214
+ raise Thor::Error, "No value provided for required options #{opts}" unless opts.empty?
215
+ end
216
+
217
+ include Tebako::CliHelpers
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,165 @@
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 "options_manager"
36
+ require_relative "scenario_manager"
37
+ require_relative "packager_lite"
38
+
39
+ # Tebako - an executable packager
40
+ # Command-line interface methods
41
+ module Tebako
42
+ # Cli helpers
43
+ module CliHelpers
44
+ WARN = <<~WARN
45
+
46
+ ******************************************************************************************************************
47
+ * *
48
+ * WARNING: You are packaging in-place, i.e.: tebako package will be placed inside application root. *
49
+ * It is not an error but we do not recommend it because it is a way to keep packaging old versions recrsively. *
50
+ * *
51
+ * For example, ensure that `--root=` differs from `--output=` as described in README.adoc: *
52
+ * tebako press --root='~/projects/myproject' --entry=start.rb --output=/temp/myproject.tebako *
53
+ * *
54
+ ******************************************************************************************************************
55
+
56
+ WARN
57
+
58
+ WARN2 = <<~WARN
59
+
60
+ ******************************************************************************************************************
61
+ * *
62
+ * WARNING: You are creating packaging environment inside application root. *
63
+ * It is not an error but it means that all build-time artifacts will ne included in tebako package. *
64
+ * You do not need it unless under very special circumstances like tebako packaging tebako itself. *
65
+ * *
66
+ * Please consider removing your exisitng `--prefix` folder abd use another one that points outside of `--root` *
67
+ * like tebako press --r ~/projects/myproject -e start.rb -o /temp/myproject.tebako -p ~/.tebako *
68
+ * *
69
+ ******************************************************************************************************************
70
+
71
+ WARN
72
+
73
+ def check_warnings(options_manager)
74
+ return unless options_manager.mode != "runtime"
75
+
76
+ puts WARN if options_manager.package_within_root?
77
+ puts WARN2 if options_manager.prefix_within_root?
78
+ sleep 5
79
+ end
80
+
81
+ def do_press(options_manager)
82
+ scenario_manager = Tebako::ScenarioManager.new(options_manager.root, options_manager.fs_entrance)
83
+ scenario_manager.configure_scenario
84
+ options_manager.process_gemfile(scenario_manager.gemfile_path) if scenario_manager.with_gemfile
85
+ check_warnings(options_manager)
86
+ puts options_manager.press_announce(scenario_manager.msys?)
87
+
88
+ do_press_runtime(options_manager, scenario_manager)
89
+ do_press_application(options_manager, scenario_manager)
90
+ end
91
+
92
+ def do_press_application(options_manager, scenario_manager)
93
+ return unless %w[both application].include?(options_manager.mode)
94
+
95
+ packager = Tebako::PackagerLite.new(options_manager, scenario_manager)
96
+ packager.create_package
97
+ end
98
+
99
+ def do_press_runtime(options_manager, scenario_manager)
100
+ return unless %w[both runtime bundle].include?(options_manager.mode)
101
+
102
+ generate_files(options_manager, scenario_manager)
103
+ merged_env = ENV.to_h.merge(scenario_manager.b_env)
104
+ Tebako.packaging_error(103) unless system(merged_env, press_cfg_cmd(options_manager))
105
+ Tebako.packaging_error(104) unless system(merged_env, press_build_cmd(options_manager))
106
+ finalize(options_manager, scenario_manager)
107
+ end
108
+
109
+ def do_setup(options_manager)
110
+ puts "Setting up tebako packaging environment"
111
+
112
+ merged_env = ENV.to_h.merge(Tebako::ScenarioManagerBase.new.b_env)
113
+ Tebako.packaging_error(101) unless system(merged_env, setup_cfg_cmd(options_manager))
114
+ Tebako.packaging_error(102) unless system(merged_env, setup_build_cmd(options_manager))
115
+ end
116
+
117
+ def generate_files(options_manager, scenario_manager)
118
+ puts "-- Generating files"
119
+
120
+ v_parts = Tebako::VERSION.split(".")
121
+ Tebako::Codegen.generate_tebako_version_h(options_manager, v_parts)
122
+ Tebako::Codegen.generate_tebako_fs_cpp(options_manager, scenario_manager)
123
+ Tebako::Codegen.generate_deploy_rb(options_manager, scenario_manager)
124
+
125
+ return unless %w[both runtime].include?(options_manager.mode)
126
+
127
+ Tebako::Codegen.generate_stub_rb(options_manager)
128
+ end
129
+
130
+ def finalize(options_manager, scenario_manager)
131
+ use_patchelf = options_manager.patchelf? && scenario_manager.linux_gnu?
132
+ patchelf = use_patchelf ? "#{options_manager.deps_bin_dir}/patchelf" : nil
133
+ Tebako::Packager.finalize(options_manager.ruby_src_dir, options_manager.package,
134
+ options_manager.rv, patchelf, options_manager.output_type_first)
135
+ end
136
+
137
+ def options_from_tebafile(tebafile)
138
+ ::YAML.load_file(tebafile)["options"] || {}
139
+ rescue Psych::SyntaxError => e
140
+ puts "Warning: The tebafile '#{tebafile}' contains invalid YAML syntax."
141
+ puts e.message
142
+ {}
143
+ rescue StandardError => e
144
+ puts "An unexpected error occurred while loading the tebafile '#{tebafile}'."
145
+ puts e.message
146
+ {}
147
+ end
148
+
149
+ def press_build_cmd(options_manager)
150
+ "cmake --build #{options_manager.output_folder} --target tebako --parallel #{Etc.nprocessors}"
151
+ end
152
+
153
+ def press_cfg_cmd(options_manager)
154
+ "cmake -DSETUP_MODE:BOOLEAN=OFF #{options_manager.cfg_options} #{options_manager.press_options}"
155
+ end
156
+
157
+ def setup_build_cmd(options_manager)
158
+ "cmake --build \"#{options_manager.output_folder}\" --target setup --parallel #{Etc.nprocessors}"
159
+ end
160
+
161
+ def setup_cfg_cmd(options_manager)
162
+ "cmake -DSETUP_MODE:BOOLEAN=ON #{options_manager.cfg_options}"
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,252 @@
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 "pathname"
29
+ require "fileutils"
30
+
31
+ require_relative "package_descriptor"
32
+
33
+ # Tebako - an executable packager
34
+ module Tebako
35
+ # Code geberation
36
+ module Codegen
37
+ COMMON_C_HEADER = <<~SUBST
38
+ /**
39
+ * THIS FILE WAS GENERATED AUTOMATICALLY BY TEBAKO. DO NOT CHANGE IT, PLEASE
40
+ **/
41
+
42
+ SUBST
43
+
44
+ COMMON_RUBY_HEADER = <<~SUBST
45
+ #!/usr/bin/env ruby
46
+ # frozen_string_literal: true
47
+
48
+ # THIS FILE WAS GENERATED AUTOMATICALLY BY TEBAKO. DO NOT CHANGE IT, PLEASE
49
+
50
+ SUBST
51
+
52
+ class << self # rubocop:disable Metrics/ClassLength
53
+ def deploy_crt_implib(opt, scm)
54
+ crt = ""
55
+ if scm.msys?
56
+ crt = <<~SUBST
57
+ Tebako::Packager.create_implib("#{opt.ruby_src_dir}", "#{opt.data_src_dir}",
58
+ "#{opt.package}", rv)
59
+ SUBST
60
+ end
61
+ crt
62
+ end
63
+
64
+ def deploy_mk(opt, scm)
65
+ case opt.mode
66
+ when "bundle"
67
+ deploy_mk_bundle(opt, scm)
68
+ when /runtime|both/
69
+ deploy_mk_stub(opt)
70
+ end
71
+ end
72
+
73
+ def deploy_mk_bundle(opt, scm)
74
+ <<~SUBST
75
+ Tebako::Packager.deploy("#{opt.data_src_dir}", "#{opt.data_pre_dir}",
76
+ rv , "#{opt.root}", "#{scm.fs_entrance}", "#{opt.cwd}")
77
+ Tebako::Packager.mkdwarfs("#{opt.deps_bin_dir}", "#{opt.data_bundle_file}",
78
+ "#{opt.data_src_dir}")
79
+ SUBST
80
+ end
81
+
82
+ def deploy_mk_stub(opt)
83
+ <<~SUBST
84
+ Tebako::Packager.deploy("#{opt.data_src_dir}", "#{opt.data_pre_dir}",
85
+ rv, "#{File.join(opt.deps, "src", "tebako", "local")}", "stub.rb", nil)
86
+ Tebako::Packager.mkdwarfs("#{opt.deps_bin_dir}", "#{opt.data_stub_file}", "#{opt.data_src_dir}")
87
+ SUBST
88
+ end
89
+
90
+ def deploy_rb(opt, scm)
91
+ <<~SUBST
92
+ #{deploy_rq}
93
+
94
+ begin
95
+ #{deploy_rb_inner(opt, scm)}
96
+ rescue Tebako::Error => e
97
+ puts "deploy script failed: \#{e.message} [\#{e.error_code}]"
98
+ exit(e.error_code)
99
+ end
100
+ SUBST
101
+ end
102
+
103
+ def deploy_rb_inner(opt, scm)
104
+ <<~SUBST
105
+ rv = Tebako::RubyVersion.new(ARGV[0])
106
+ stash = File.join("#{opt.deps}", "stash_\#{ARGV[0]}")
107
+ Tebako::Packager::init(stash.to_s, "#{opt.data_src_dir}",
108
+ "#{opt.data_pre_dir}", "#{opt.data_bin_dir}")
109
+ #{deploy_crt_implib(opt, scm)}
110
+ #{deploy_mk(opt, scm)}
111
+ SUBST
112
+ end
113
+
114
+ def deploy_rq
115
+ <<~SUBST
116
+ require "#{File.join(__dir__, "error.rb")}"
117
+ require "#{File.join(__dir__, "package_descriptor.rb")}"
118
+ require "#{File.join(__dir__, "packager.rb")}"
119
+ require "#{File.join(__dir__, "ruby_version.rb")}"
120
+ SUBST
121
+ end
122
+
123
+ def stub_rb(opt)
124
+ <<~SUBST
125
+ puts "Copyright (c) 2024-2025 Ribose Inc (https://www.ribose.com)"
126
+ puts "Tebako runtime stub v#{Tebako::VERSION}"
127
+ puts "To run your application please call #{File.basename(opt.package)} --tebako-run <your tebako package>"
128
+ SUBST
129
+ end
130
+
131
+ def generate_stub_rb(options_manager)
132
+ puts " ... stub.rb"
133
+
134
+ fname = File.join(options_manager.deps, "src", "tebako", "local", "stub.rb")
135
+ FileUtils.mkdir_p(File.dirname(fname))
136
+
137
+ File.open(fname, "w") do |file|
138
+ file.write(COMMON_RUBY_HEADER)
139
+ file.write(stub_rb(options_manager))
140
+ end
141
+ end
142
+
143
+ def generate_deploy_rb(options_manager, scenario_manager)
144
+ puts " ... deploy.rb"
145
+
146
+ fname = File.join(options_manager.deps, "bin", "deploy.rb")
147
+ FileUtils.mkdir_p(File.dirname(fname))
148
+
149
+ File.open(fname, "w") do |file|
150
+ file.write(COMMON_RUBY_HEADER)
151
+ file.write(deploy_rb(options_manager, scenario_manager))
152
+ end
153
+ end
154
+
155
+ def generate_package_descriptor(options_manager, scenario_manager)
156
+ puts " ... package_descriptor"
157
+ fname = File.join(options_manager.deps, "src", "tebako", "package_descriptor")
158
+ FileUtils.mkdir_p(File.dirname(fname))
159
+ descriptor = Tebako::PackageDescriptor.new(options_manager.ruby_ver, Tebako::VERSION,
160
+ scenario_manager.fs_mount_point, scenario_manager.fs_entry_point,
161
+ options_manager.cwd)
162
+ File.binwrite(fname, descriptor.serialize)
163
+ fname
164
+ end
165
+
166
+ def generate_tebako_fs_cpp(options_manager, scenario_manager)
167
+ puts " ... tebako-fs.cpp"
168
+
169
+ fname = File.join(options_manager.deps, "src", "tebako", "tebako-fs.cpp")
170
+ FileUtils.mkdir_p(File.dirname(fname))
171
+
172
+ File.open(fname, "w") do |file|
173
+ file.write(COMMON_C_HEADER)
174
+ file.write(tebako_fs_cpp(options_manager, scenario_manager))
175
+ end
176
+ end
177
+
178
+ def generate_tebako_version_h(options_manager, v_parts)
179
+ puts " ... tebako-version.h"
180
+
181
+ fname = File.join(options_manager.deps, "include", "tebako", "tebako-version.h")
182
+ FileUtils.mkdir_p(File.dirname(fname))
183
+
184
+ File.open(fname, "w") do |file|
185
+ file.write(COMMON_C_HEADER)
186
+ file.write(tebako_version_h(v_parts))
187
+ end
188
+ end
189
+
190
+ def package_cwd(options_manager, scenario_manager)
191
+ if options_manager.cwd.nil?
192
+ "nullptr"
193
+ else
194
+ "\"#{scenario_manager.fs_mount_point}/#{options_manager.cwd}\""
195
+ end
196
+ end
197
+
198
+ def tebako_fs_cpp(options_manager, scenario_manager)
199
+ case options_manager.mode
200
+ when "bundle"
201
+ tebako_fs_cpp_bundle(options_manager, scenario_manager)
202
+ when /runtime|both/
203
+ tebako_fs_cpp_stub(options_manager, scenario_manager)
204
+ end
205
+ end
206
+
207
+ def tebako_fs_cpp_bundle(options_manager, scenario_manager)
208
+ <<~SUBST
209
+ #include <limits.h>
210
+ #include <incbin/incbin.h>
211
+
212
+ namespace tebako {
213
+ const char * fs_log_level = "#{options_manager.l_level}";
214
+ const char * fs_mount_point = "#{scenario_manager.fs_mount_point}";
215
+ const char * fs_entry_point = "#{scenario_manager.fs_entry_point}";
216
+ const char * package_cwd = #{package_cwd(options_manager, scenario_manager)};
217
+ char original_cwd[PATH_MAX];
218
+
219
+ INCBIN(fs, "#{options_manager.data_bundle_file}");
220
+ }
221
+ SUBST
222
+ end
223
+
224
+ def tebako_fs_cpp_stub(options_manager, scenario_manager)
225
+ <<~SUBST
226
+ #include <limits.h>
227
+ #include <incbin/incbin.h>
228
+
229
+ namespace tebako {
230
+ const char * fs_log_level = "#{options_manager.l_level}";
231
+ const char * fs_mount_point = "#{scenario_manager.fs_mount_point}";
232
+ const char * fs_entry_point = "/local/stub.rb";
233
+ const char * package_cwd = nullptr;
234
+ char original_cwd[PATH_MAX];
235
+
236
+ INCBIN(fs, "#{options_manager.data_stub_file}");
237
+ }
238
+ SUBST
239
+ end
240
+
241
+ def tebako_version_h(v_parts)
242
+ <<~SUBST
243
+ #pragma once
244
+
245
+ const unsigned int tebako_version_major = #{v_parts[0]};
246
+ const unsigned int tebako_version_minor = #{v_parts[1]};
247
+ const unsigned int tebako_version_teeny = #{v_parts[2]};
248
+ SUBST
249
+ end
250
+ end
251
+ end
252
+ end