tebako 0.12.8 → 0.12.10

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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024 [Ribose Inc](https://www.ribose.com).
3
+ # Copyright (c) 2024-2025 [Ribose Inc](https://www.ribose.com).
4
4
  # All rights reserved.
5
5
  # This file is a part of tebako
6
6
  #
@@ -32,64 +32,99 @@ require_relative "error"
32
32
 
33
33
  # Tebako - an executable packager
34
34
  module Tebako
35
- # Manages packaging scenario based on input files (gemfile, gemspec, etc)
36
- class ScenarioManager
37
- def initialize(fs_root, fs_entrance)
38
- @with_gemfile = false
39
- initialize_root(fs_root)
40
- initialize_entry_point(fs_entrance || "stub.rb")
35
+ # Magic version numbers used to ensure compatibility for Ruby 2.7.x, 3.0.x
36
+ # These are the minimal versions required to provide linux-gnu / linux-musl differentiation by bundler
37
+ # Ruby 3.1+ default rubygems versions work correctly out of the box
38
+ BUNDLER_VERSION = "2.4.22"
39
+ RUBYGEMS_VERSION = "3.4.22"
40
+
41
+ # A couple of static Scenario definitions
42
+ class ScenarioManagerBase
43
+ def initialize(ostype = RUBY_PLATFORM)
44
+ @ostype = ostype
45
+ @linux = @ostype =~ /linux/ ? true : false
46
+ @musl = @ostype =~ /linux-musl/ ? true : false
47
+ @macos = @ostype =~ /darwin/ ? true : false
48
+ @msys = @ostype =~ /msys|mingw|cygwin/ ? true : false
49
+
50
+ @fs_mount_point = @msys ? "A:/__tebako_memfs__" : "/__tebako_memfs__"
51
+ @exe_suffix = @msys ? ".exe" : ""
41
52
  end
42
53
 
43
- attr_reader :fs_entry_point, :fs_mount_point, :fs_entrance, :gemfile_path, :with_gemfile
54
+ attr_reader :fs_mount_point, :exe_suffix
44
55
 
45
- def configure_scenario
46
- @fs_mount_point = if msys?
47
- "A:/__tebako_memfs__"
48
- else
49
- "/__tebako_memfs__"
50
- end
56
+ def b_env
57
+ u_flags = if @macos
58
+ "-DTARGET_OS_SIMULATOR=0 -DTARGET_OS_IPHONE=0 #{ENV.fetch("CXXFLAGS", nil)}"
59
+ else
60
+ ENV.fetch("CXXFLAGS", nil)
61
+ end
62
+ @b_env ||= { "CXXFLAGS" => u_flags }
63
+ end
51
64
 
52
- lookup_files
53
- configure_scenario_inner
65
+ def linux?
66
+ @linux
54
67
  end
55
68
 
56
- def exe_suffix
57
- @exe_suffix ||= msys? ? ".exe" : ""
69
+ def m_files
70
+ # [TODO]
71
+ # Ninja generates incorrect script for tebako press target -- gets lost in a chain custom targets
72
+ # Using makefiles has negative performance impact so it needs to be fixed
73
+
74
+ @m_files ||= if @linux || @macos
75
+ "Unix Makefiles"
76
+ elsif @msys
77
+ "MinGW Makefiles"
78
+ else
79
+ raise Tebako::Error.new("#{RUBY_PLATFORM} is not supported.", 112)
80
+ end
58
81
  end
59
82
 
60
83
  def macos?
61
- @macos ||= RUBY_PLATFORM =~ /darwin/ ? true : false
84
+ @macos
62
85
  end
63
86
 
64
87
  def msys?
65
- @msys ||= RUBY_PLATFORM =~ /msys|mingw|cygwin/ ? true : false
88
+ @msys
66
89
  end
67
90
 
68
- private
69
-
70
- def initialize_entry_point(fs_entrance)
71
- @fs_entrance = Pathname.new(fs_entrance).cleanpath.to_s
91
+ def musl?
92
+ @musl
93
+ end
72
94
 
73
- if Pathname.new(@fs_entrance).absolute?
74
- Tebako.packaging_error 114 unless @fs_entrance.start_with?(@fs_root)
95
+ def ncores
96
+ if @ncores.nil?
97
+ if @macos
98
+ out, st = Open3.capture2e("sysctl", "-n", "hw.ncpu")
99
+ else
100
+ out, st = Open3.capture2e("nproc", "--all")
101
+ end
75
102
 
76
- fetmp = @fs_entrance
77
- @fs_entrance = Pathname.new(@fs_entrance).relative_path_from(Pathname.new(@fs_root)).to_s
78
- puts "-- Absolute path to entry point '#{fetmp}' will be reduced to '#{@fs_entrance}' relative to '#{@fs_root}'"
103
+ @ncores = !st.signaled? && st.exitstatus.zero? ? out.strip.to_i : 4
79
104
  end
80
- # Can check after deploy, because entry point can be generated during bundle install or gem install
81
- # Tebako.packaging_error 106 unless File.file?(File.join(@fs_root, @fs_entrance))
82
- @fs_entry_point = "/bin/#{@fs_entrance}"
105
+ @ncores
83
106
  end
107
+ end
84
108
 
85
- def initialize_root(fs_root)
86
- Tebako.packaging_error 107 unless Dir.exist?(fs_root)
87
- p_root = Pathname.new(fs_root).cleanpath
88
- Tebako.packaging_error 113 unless p_root.absolute?
89
- @fs_root = p_root.realpath.to_s
109
+ # Manages packaging scenario based on input files (gemfile, gemspec, etc)
110
+ class ScenarioManager < ScenarioManagerBase
111
+ def initialize(fs_root, fs_entrance)
112
+ super()
113
+ @with_gemfile = @with_lockfile = @needs_bundler = false
114
+ @bundler_version = BUNDLER_VERSION
115
+ initialize_root(fs_root)
116
+ initialize_entry_point(fs_entrance || "stub.rb")
117
+ end
118
+
119
+ attr_reader :fs_entry_point, :fs_entrance, :gemfile_path, :needs_bundler, :with_gemfile
120
+
121
+ def bundler_reference
122
+ @needs_bundler ? "_#{@bundler_version}_" : nil
90
123
  end
91
124
 
92
- def configure_scenario_inner
125
+ def configure_scenario
126
+ lookup_files
127
+
93
128
  case @gs_length
94
129
  when 0
95
130
  configure_scenario_no_gemspec
@@ -100,6 +135,8 @@ module Tebako
100
135
  end
101
136
  end
102
137
 
138
+ private
139
+
103
140
  def configure_scenario_no_gemspec
104
141
  @fs_entry_point = "/local/#{@fs_entrance}" if @with_gemfile || @g_length.zero?
105
142
 
@@ -112,11 +149,93 @@ module Tebako
112
149
  end
113
150
  end
114
151
 
152
+ def initialize_entry_point(fs_entrance)
153
+ @fs_entrance = Pathname.new(fs_entrance).cleanpath.to_s
154
+
155
+ if Pathname.new(@fs_entrance).absolute?
156
+ Tebako.packaging_error 114 unless @fs_entrance.start_with?(@fs_root)
157
+
158
+ fetmp = @fs_entrance
159
+ @fs_entrance = Pathname.new(@fs_entrance).relative_path_from(Pathname.new(@fs_root)).to_s
160
+ puts "-- Absolute path to entry point '#{fetmp}' will be reduced to '#{@fs_entrance}' relative to '#{@fs_root}'"
161
+ end
162
+ # Can check after deploy, because entry point can be generated during bundle install or gem install
163
+ # Tebako.packaging_error 106 unless File.file?(File.join(@fs_root, @fs_entrance))
164
+ @fs_entry_point = "/bin/#{@fs_entrance}"
165
+ end
166
+
167
+ def initialize_root(fs_root)
168
+ Tebako.packaging_error 107 unless Dir.exist?(fs_root)
169
+ p_root = Pathname.new(fs_root).cleanpath
170
+ Tebako.packaging_error 113 unless p_root.absolute?
171
+ @fs_root = p_root.realpath.to_s
172
+ end
173
+
115
174
  def lookup_files
116
- @gemfile_path = File.join(@fs_root, "Gemfile")
117
175
  @gs_length = Dir.glob(File.join(@fs_root, "*.gemspec")).length
118
- @with_gemfile = File.exist?(@gemfile_path)
119
176
  @g_length = Dir.glob(File.join(@fs_root, "*.gem")).length
177
+ @with_gemfile = File.exist?(@gemfile_path = File.join(@fs_root, "Gemfile"))
178
+ @with_lockfile = File.exist?(@lockfile_path = File.join(@fs_root, "Gemfile.lock"))
179
+ end
180
+ end
181
+
182
+ # Configure scenraio and do bundler resolution
183
+ class ScenarioManagerWithBundler < ScenarioManager
184
+ protected
185
+
186
+ def lookup_files
187
+ super
188
+ if @with_lockfile
189
+ update_bundler_version_from_lockfile(@lockfile_path)
190
+ elsif @with_gemfile
191
+ update_bundler_version_from_gemfile(@gemfile_path)
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ def store_compatible_bundler_version(requirement)
198
+ fetcher = Gem::SpecFetcher.fetcher
199
+ tuples = fetcher.detect(:released) do |name_tuple|
200
+ name_tuple.name == "bundler" && requirement.satisfied_by?(name_tuple.version)
201
+ end
202
+
203
+ Tebako.packaging_error 119 if tuples.empty?
204
+
205
+ # Get latest compatible version
206
+ @bundler_version = tuples.map { |tuple, _| tuple.version }.max.to_s
207
+ end
208
+
209
+ def update_bundler_version_from_gemfile(gemfile_path)
210
+ # Build definition without lockfile
211
+ definition = Bundler::Definition.build(gemfile_path, nil, nil)
212
+
213
+ # Get bundler dependency from Gemfile
214
+ bundler_dep = definition.dependencies.find { |d| d.name == "bundler" }
215
+
216
+ return unless bundler_dep
217
+
218
+ @needs_bundler = true
219
+ min_requirement = Gem::Requirement.create(">= #{Tebako::BUNDLER_VERSION}")
220
+ requirement = Gem::Requirement.create(bundler_dep.requirement, min_requirement)
221
+
222
+ store_compatible_bundler_version(requirement)
223
+ end
224
+
225
+ def update_bundler_version_from_lockfile(lockfile_path)
226
+ puts " ... using lockfile at #{@lockfile_path}"
227
+ Tebako.packaging_error 117 unless File.exist?(lockfile_path)
228
+
229
+ lockfile_content = File.read(lockfile_path)
230
+ Tebako.packaging_error 117 unless lockfile_content =~ /BUNDLED WITH\n\s+(#{Gem::Version::VERSION_PATTERN})\n/
231
+
232
+ @bundler_version = ::Regexp.last_match(1)
233
+ @needs_bundler = true
234
+
235
+ bundler_requirement = Gem::Requirement.new(">= #{BUNDLER_VERSION}")
236
+ return if bundler_requirement.satisfied_by?(Gem::Version.new(@bundler_version))
237
+
238
+ Tebako.packaging_error 118, " : #{@bundler_version} requested, #{BUNDLER_VERSION} minimum required"
120
239
  end
121
240
  end
122
241
  end
@@ -26,5 +26,5 @@
26
26
  # POSSIBILITY OF SUCH DAMAGE.
27
27
 
28
28
  module Tebako
29
- VERSION = "0.12.8"
29
+ VERSION = "0.12.10"
30
30
  end
data/tebako.gemspec CHANGED
@@ -63,8 +63,10 @@ Gem::Specification.new do |spec|
63
63
  spec.add_dependency "thor", "~> 1.2"
64
64
  spec.add_dependency "yaml", "~> 0.2.1"
65
65
 
66
+ spec.add_development_dependency "debug"
66
67
  spec.add_development_dependency "hoe"
67
68
  spec.add_development_dependency "minitest"
69
+ spec.add_development_dependency "rdbg"
68
70
  spec.add_development_dependency "rspec", "~> 3.2"
69
71
  spec.add_development_dependency "rubocop", "~> 1.52"
70
72
  spec.add_development_dependency "rubocop-rubycw"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tebako
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.8
4
+ version: 0.12.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-25 00:00:00.000000000 Z
11
+ date: 2025-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.2.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: debug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: hoe
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rdbg
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: rspec
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -190,13 +218,14 @@ files:
190
218
  - lib/tebako/packager.rb
191
219
  - lib/tebako/packager/pass1_patch.rb
192
220
  - lib/tebako/packager/pass1a_patch.rb
193
- - lib/tebako/packager/pass2.rb
221
+ - lib/tebako/packager/pass2_patch.rb
194
222
  - lib/tebako/packager/patch.rb
195
223
  - lib/tebako/packager/patch_buildsystem.rb
196
224
  - lib/tebako/packager/patch_helpers.rb
197
225
  - lib/tebako/packager/patch_libraries.rb
198
226
  - lib/tebako/packager/patch_literals.rb
199
227
  - lib/tebako/packager/patch_main.rb
228
+ - lib/tebako/packager/rubygems_patch.rb
200
229
  - lib/tebako/packager_lite.rb
201
230
  - lib/tebako/ruby_builder.rb
202
231
  - lib/tebako/ruby_version.rb
@@ -1,149 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2021-2024 [Ribose Inc](https://www.ribose.com).
4
- # All rights reserved.
5
- # This file is a part of tebako
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 "patch_literals"
29
- require_relative "patch_main"
30
- require_relative "patch_libraries"
31
- require_relative "patch_helpers"
32
- require_relative "patch_buildsystem"
33
-
34
- # Tebako - an executable packager
35
- module Tebako
36
- module Packager
37
- # Ruby patching definitions (pass2)
38
- module Pass2
39
- class << self
40
- def get_patch_map(ostype, deps_lib_dir, ruby_ver)
41
- patch_map = get_patch_map_base(ostype, deps_lib_dir, ruby_ver)
42
- patch_map.store("thread_pthread.c", LINUX_MUSL_THREAD_PTHREAD_PATCH) if ostype =~ /linux-musl/
43
- if PatchHelpers.msys?(ostype)
44
- patch_map.merge!(get_msys_patches(ruby_ver))
45
- elsif ruby_ver.ruby3x?
46
- patch_map.store("common.mk", COMMON_MK_PATCH)
47
- end
48
- extend_patch_map_r33(patch_map, ostype, deps_lib_dir, ruby_ver)
49
- patch_map.store("prism_compile.c", PRISM_PATCHES) if ruby_ver.ruby34?
50
- patch_map
51
- end
52
-
53
- private
54
-
55
- include Tebako::Packager::PatchBuildsystem
56
- include Tebako::Packager::PatchLiterals
57
- def extend_patch_map_r33(patch_map, ostype, deps_lib_dir, ruby_ver)
58
- if ruby_ver.ruby33? || PatchHelpers.msys?(ostype)
59
- patch_map.store("config.status",
60
- get_config_status_patch(ostype, deps_lib_dir, ruby_ver))
61
- end
62
- patch_map
63
- end
64
-
65
- def get_dir_c_patch(ostype)
66
- pattern = PatchHelpers.msys?(ostype) ? "/* define system APIs */" : "#ifdef HAVE_GETATTRLIST"
67
- dir_c_patch = PatchHelpers.patch_c_file_pre(pattern)
68
- dir_c_patch.merge!(DIR_C_BASE_PATCH)
69
- dir_c_patch
70
- end
71
-
72
- def get_dln_c_patch(ostype, ruby_ver)
73
- pattern = "#ifndef dln_loaderror"
74
- # Not using substitutions of dlxxx functions on Windows
75
- dln_c_patch = {
76
- pattern => "#{PatchHelpers.msys?(ostype) ? C_FILE_SUBST_LESS : C_FILE_SUBST}\n#{pattern}\n"
77
- }
78
-
79
- if PatchHelpers.msys?(ostype)
80
- patch = ruby_ver.ruby32? ? DLN_C_MSYS_PATCH : DLN_C_MSYS_PATCH_PRE32
81
- dln_c_patch.merge!(patch)
82
- end
83
-
84
- dln_c_patch
85
- end
86
-
87
- def get_io_c_msys_patch(ruby_ver)
88
- io_c_msys_patch = ruby_ver.ruby32? ? IO_C_MSYS_PATCH : IO_C_MSYS_PATCH_PRE_32
89
- io_c_msys_patch.merge(IO_C_MSYS_BASE_PATCH)
90
- end
91
-
92
- def get_io_c_patch(ostype, ruby_ver)
93
- io_c_patch = PatchHelpers.patch_c_file_pre("/* define system APIs */")
94
- io_c_patch.merge!(get_io_c_msys_patch(ruby_ver)) if PatchHelpers.msys?(ostype)
95
- io_c_patch
96
- end
97
-
98
- def get_util_c_patch(ruby_ver)
99
- if ruby_ver.ruby31?
100
- PatchHelpers.patch_c_file_post("#endif /* !HAVE_GNU_QSORT_R */")
101
- else
102
- PatchHelpers.patch_c_file_pre("#ifndef S_ISDIR")
103
- end
104
- end
105
-
106
- def get_tool_mkconfig_rb_patch(ostype)
107
- subst = PatchHelpers.msys?(ostype) ? TOOL_MKCONFIG_RB_SUBST_MSYS : TOOL_MKCONFIG_RB_SUBST
108
- {
109
- " if fast[name]" => subst
110
- }
111
- end
112
-
113
- def get_msys_patches(ruby_ver)
114
- {
115
- "cygwin/GNUmakefile.in" => get_gnumakefile_in_patch_p2(ruby_ver),
116
- "ruby.c" => RUBY_C_MSYS_PATCHES,
117
- "win32/file.c" => WIN32_FILE_C_MSYS_PATCHES,
118
- "win32/win32.c" => WIN32_WIN32_C_MSYS_PATCHES
119
- }
120
- end
121
-
122
- def get_patch_map_base(ostype, deps_lib_dir, ruby_ver)
123
- {
124
- "template/Makefile.in" => template_makefile_in_patch(ostype, deps_lib_dir, ruby_ver),
125
- "tool/mkconfig.rb" => get_tool_mkconfig_rb_patch(ostype),
126
- "dir.c" => get_dir_c_patch(ostype), "dln.c" => get_dln_c_patch(ostype, ruby_ver),
127
- "io.c" => get_io_c_patch(ostype, ruby_ver), "main.c" => PatchMain.get_main_c_patch(ruby_ver),
128
- "file.c" => PatchHelpers.patch_c_file_pre("/* define system APIs */"),
129
- "util.c" => get_util_c_patch(ruby_ver)
130
- }
131
- end
132
-
133
- def mlibs_subst(ostype, deps_lib_dir, ruby_ver)
134
- yjit_libs = ruby_ver.ruby32only? ? "$(YJIT_LIBS) " : ""
135
- {
136
- "MAINLIBS = #{yjit_libs}@MAINLIBS@" =>
137
- "# -- Start of tebako patch -- \n" \
138
- "MAINLIBS = #{yjit_libs}#{PatchLibraries.mlibs(ostype, deps_lib_dir, ruby_ver, true)}\n" \
139
- "# -- End of tebako patch -- \n"
140
- }
141
- end
142
-
143
- def template_makefile_in_patch(ostype, deps_lib_dir, ruby_ver)
144
- template_makefile_in_patch_two(ostype, ruby_ver).merge(mlibs_subst(ostype, deps_lib_dir, ruby_ver))
145
- end
146
- end
147
- end
148
- end
149
- end