Class: Tebako::OptionsManager

Inherits:
Object
  • Object
show all
Defined in:
lib/tebako/options_manager.rb

Overview

Cli helpers

Constant Summary collapse

THREE_PART_MODES =

Press modes producing three-part packages (tebako-bootstrap + image slots + tpkg trailer): 'lean' resolves the runtime at first run, 'fat' additionally embeds it as a payload slot (self-installing, offline)

%w[lean fat].freeze
PREBUILT_DEFAULT_MODES =

Modes whose default runtime provenance is a prebuilt runtime package

%w[bundle classic lean fat].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ OptionsManager

Returns a new instance of OptionsManager.



51
52
53
54
55
56
# File 'lib/tebako/options_manager.rb', line 51

def initialize(options)
  @options = options
  @rv = Tebako::RubyVersion.new(@options["Ruby"])
  @ruby_ver, @ruby_hash = @rv.extend_ruby_version
  @scmb = ScenarioManagerBase.new
end

Instance Attribute Details

#ruby_verObject (readonly)

Returns the value of attribute ruby_ver.



58
59
60
# File 'lib/tebako/options_manager.rb', line 58

def ruby_ver
  @ruby_ver
end

#rvObject (readonly)

Returns the value of attribute rv.



58
59
60
# File 'lib/tebako/options_manager.rb', line 58

def rv
  @rv
end

Instance Method Details

#cfg_optionsObject



60
61
62
63
64
65
66
67
68
69
# File 'lib/tebako/options_manager.rb', line 60

def cfg_options
  ## {v_parts[3]} may be something like rc1 that won't work with CMake
  v_parts = Tebako::VERSION.split(".")
  # Cannot use 'xxx' as parameters because it does not work in Windows shells
  # So we have to use \"xxx\"
  @cfg_options ||=
    "-DCMAKE_BUILD_TYPE=Release -DRUBY_VER:STRING=\"#{@ruby_ver}\" -DRUBY_HASH:STRING=\"#{@ruby_hash}\" " \
    "-DDEPS:STRING=\"#{deps}\" -G \"#{@scmb.m_files}\" -B \"#{output_folder}\" -S \"#{source}\" " \
    "#{remove_glibc_private} -DTEBAKO_VERSION:STRING=\"#{v_parts[0]}.#{v_parts[1]}.#{v_parts[2]}\""
end

#cwdObject



71
72
73
74
# File 'lib/tebako/options_manager.rb', line 71

def cwd
  f_cwd = @options["cwd"]&.gsub("\\", "/")
  @cwd ||= f_cwd
end

#cwd_announceObject



76
77
78
# File 'lib/tebako/options_manager.rb', line 76

def cwd_announce
  @cwd_announce ||= cwd.nil? ? "<Host current directory>" : cwd
end

#data_app_fileObject



100
101
102
# File 'lib/tebako/options_manager.rb', line 100

def data_app_file
  @data_app_file ||= File.join(data_bin_dir, "fs2.bin")
end

#data_bin_dirObject

DATA_BIN_DIR folder is used to create packaged filesystem set(DATA_BIN_DIR $CMAKE_CURRENT_BINARY_DIR/p)



82
83
84
# File 'lib/tebako/options_manager.rb', line 82

def data_bin_dir
  @data_bin_dir ||= File.join(output_folder, "p")
end

#data_bundle_fileObject

Mode File(s) Content bundle fs.bin Application both fs.bin, fs2.bin Stub, application respectively runtime fs.bin Stub app fs2.bin Application



92
93
94
# File 'lib/tebako/options_manager.rb', line 92

def data_bundle_file
  @data_bundle_file ||= File.join(data_bin_dir, "fs.bin")
end

#data_pre_dirObject

DATA_PRE_DIR folder is used to build gems that need to be packaged set(DATA_PRE_DIR $CMAKE_CURRENT_BINARY_DIR/r)



106
107
108
# File 'lib/tebako/options_manager.rb', line 106

def data_pre_dir
  @data_pre_dir ||= File.join(output_folder, "r")
end

#data_src_dirObject

DATA_SRC_DIR folder is used to collect all files that need to be packaged set(DATA_SRC_DIR $CMAKE_CURRENT_BINARY_DIR/s)



112
113
114
# File 'lib/tebako/options_manager.rb', line 112

def data_src_dir
  @data_src_dir ||= File.join(output_folder, "s")
end

#data_stub_fileObject



96
97
98
# File 'lib/tebako/options_manager.rb', line 96

def data_stub_file
  @data_stub_file ||= File.join(data_bin_dir, "fs.bin")
end

#depsObject



116
117
118
# File 'lib/tebako/options_manager.rb', line 116

def deps
  @deps ||= File.join(prefix, "deps")
end

#deps_bin_dirObject



120
121
122
# File 'lib/tebako/options_manager.rb', line 120

def deps_bin_dir
  @deps_bin_dir ||= File.join(deps, "bin")
end

#deps_lib_dirObject



124
125
126
# File 'lib/tebako/options_manager.rb', line 124

def deps_lib_dir
  @deps_lib_dir ||= File.join(deps, "lib")
end

#fat?Boolean

Returns:

  • (Boolean)


174
175
176
# File 'lib/tebako/options_manager.rb', line 174

def fat?
  mode == "fat"
end

#folder_within_root?(folder) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
131
132
133
134
135
# File 'lib/tebako/options_manager.rb', line 128

def folder_within_root?(folder)
  folder_path = Pathname.new(folder.chomp("/"))
  root_path = Pathname.new(root.chomp("/"))
  folder_path.ascend do |path|
    return true if path == root_path
  end
  false
end

#fs_currentObject



137
138
139
140
141
142
143
144
145
# File 'lib/tebako/options_manager.rb', line 137

def fs_current
  fs_current = Dir.pwd
  if @scmb.msys?
    fs_current, cygpath_res = Open3.capture2e("cygpath", "-w", fs_current)
    Tebako.packaging_error(101) unless cygpath_res.success?
    fs_current.strip!
  end
  @fs_current ||= fs_current&.gsub("\\", "/")
end

#fs_entranceObject



147
148
149
# File 'lib/tebako/options_manager.rb', line 147

def fs_entrance
  @fs_entrance ||= @options["entry-point"]&.gsub("\\", "/")
end

#handle_nil_prefixObject



151
152
153
154
155
156
157
158
159
160
# File 'lib/tebako/options_manager.rb', line 151

def handle_nil_prefix
  env_prefix = ENV.fetch("TEBAKO_PREFIX", nil)
  if env_prefix.nil?
    puts "No prefix specified, using ~/.tebako"
    File.expand_path("~/.tebako")
  else
    puts "Using TEBAKO_PREFIX environment variable as prefix"
    File.expand_path(env_prefix.gsub("\\", "/"))
  end
end

#host_platform(ostype = RUBY_PLATFORM, arch = RbConfig::CONFIG["host_cpu"]) ⇒ Object

Platform id of the host, as used by tebako-runtime-ruby package names (e.g. "macos-arm64", "linux-gnu-x86_64")



209
210
211
# File 'lib/tebako/options_manager.rb', line 209

def host_platform(ostype = RUBY_PLATFORM, arch = RbConfig::CONFIG["host_cpu"])
  @host_platform ||= "#{host_os_id(ostype)}-#{host_arch_id(arch)}"
end

#imagesObject

Additional images for the stitched package, from repeatable '--image :' (split on the last colon so Windows drive-letter paths survive)



196
197
198
199
200
201
202
203
204
205
# File 'lib/tebako/options_manager.rb', line 196

def images
  @images ||= Array(@options["image"]).map do |spec|
    path, _sep, mount = spec.to_s.rpartition(":")
    if path.empty? || mount.empty?
      Tebako.packaging_error(130, "invalid --image specification '#{spec}' ('<path>:<mount-point>' expected)")
    end

    { path: path, mount_point: mount, format_id: Tebako::Stitcher::FORMAT_DWARFS }
  end
end

#l_levelObject



162
163
164
# File 'lib/tebako/options_manager.rb', line 162

def l_level
  @l_level ||= @options["log-level"].nil? ? "error" : @options["log-level"]
end

#modeObject



166
167
168
# File 'lib/tebako/options_manager.rb', line 166

def mode
  @mode ||= @options["mode"].nil? ? "lean" : @options["mode"]
end

#output_folderObject



213
214
215
# File 'lib/tebako/options_manager.rb', line 213

def output_folder
  @output_folder ||= File.join(prefix, "o")
end

#output_type_firstObject



217
218
219
# File 'lib/tebako/options_manager.rb', line 217

def output_type_first
  @output_type_first ||= %w[both runtime].include?(mode) ? "runtime package" : "package"
end

#output_type_secondObject



221
222
223
# File 'lib/tebako/options_manager.rb', line 221

def output_type_second
  "application package"
end

#packageObject



225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/tebako/options_manager.rb', line 225

def package
  package = if @options["output"].nil?
              File.join(Dir.pwd, mode == "runtime" ? "tebako-runtime" : File.basename(fs_entrance, ".*"))
            else
              @options["output"]&.gsub("\\", "/")
            end
  @package ||= if relative?(package)
                 File.join(fs_current, package)
               else
                 package
               end
end

#package_within_root?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'lib/tebako/options_manager.rb', line 238

def package_within_root?
  folder_within_root?(package)
end

#patchelf?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/tebako/options_manager.rb', line 242

def patchelf?
  @options["patchelf"]
end

#prebuilt_runtime?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/tebako/options_manager.rb', line 189

def prebuilt_runtime?
  runtime_source == "prebuilt"
end

#prefixObject



246
247
248
249
250
251
252
253
254
# File 'lib/tebako/options_manager.rb', line 246

def prefix
  @prefix ||= if @options["prefix"].nil?
                handle_nil_prefix
              elsif @options["prefix"] == "PWD"
                Dir.pwd
              else
                File.expand_path(@options["prefix"]&.gsub("\\", "/"))
              end
end

#prefix_within_root?Boolean

Returns:

  • (Boolean)


256
257
258
# File 'lib/tebako/options_manager.rb', line 256

def prefix_within_root?
  folder_within_root?(prefix)
end

#press_announce(is_msys) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/tebako/options_manager.rb', line 260

def press_announce(is_msys)
  case mode
  when "application"
    press_announce_application(is_msys)
  when "both"
    press_announce_both
  when "bundle", "classic", "lean", "fat"
    press_announce_bundle
  when "runtime"
    press_announce_runtime
  end
end

#press_announce_application(is_msys) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
# File 'lib/tebako/options_manager.rb', line 281

def press_announce_application(is_msys)
  <<~ANN
    Running tebako press at #{prefix}
       Mode:                      'application'
       Ruby version:              '#{@ruby_ver}'
       Project root:              '#{root}'
       Application entry point:   '#{fs_entrance}'
       Package file name:         '#{package}.tebako'#{press_announce_ref(is_msys)}
       Package working directory: '#{cwd_announce}'
  ANN
end

#press_announce_bothObject



293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/tebako/options_manager.rb', line 293

def press_announce_both
  <<~ANN
    Running tebako press at #{prefix}
       Mode:                      'both'
       Ruby version:              '#{@ruby_ver}'
       Project root:              '#{root}'
       Application entry point:   '#{fs_entrance}'
       Runtime file name:         '#{package}'
       Package file name:         '#{package}.tebako'
       Loging level:              '#{l_level}'
       Package working directory: '#{cwd_announce}'
  ANN
end

#press_announce_bundleObject



307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/tebako/options_manager.rb', line 307

def press_announce_bundle
  <<~ANN
    Running tebako press at #{prefix}
       Mode:                      '#{mode}'
       Ruby version:              '#{@ruby_ver}'
       Project root:              '#{root}'
       Application entry point:   '#{fs_entrance}'
       Package file name:         '#{package}'
       Loging level:              '#{l_level}'
       Package working directory: '#{cwd_announce}'
  ANN
end

#press_announce_ref(is_msys) ⇒ Object



273
274
275
276
277
278
279
# File 'lib/tebako/options_manager.rb', line 273

def press_announce_ref(is_msys)
  if is_msys
    " referencing runtime at '#{ref}'"
  else
    ""
  end
end

#press_announce_runtimeObject



320
321
322
323
324
325
326
327
328
# File 'lib/tebako/options_manager.rb', line 320

def press_announce_runtime
  <<~ANN
    Running tebako press at #{prefix}
       Mode:                      'runtime'
       Ruby version:              '#{@ruby_ver}'
       Runtime file name:         '#{package}'
       Loging level:              '#{l_level}'
  ANN
end

#press_optionsObject



330
331
332
# File 'lib/tebako/options_manager.rb', line 330

def press_options
  @press_options ||= "-DPCKG:STRING='#{package}' -DLOG_LEVEL:STRING='#{l_level}' " \
end

#process_gemfile(gemfile_path) ⇒ Object



334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/tebako/options_manager.rb', line 334

def process_gemfile(gemfile_path)
  folder = File.dirname(gemfile_path)
  filename = File.basename(gemfile_path)
  # Change directory to the folder containing the Gemfile
  # Because Bundler::Definition.build *sometimes* requires to be in
  # the Gemfile directory
  Dir.chdir(folder) do
    @rv = Tebako::RubyVersionWithGemfile.new(@options["Ruby"], filename)
  end
  @ruby_ver, @ruby_hash = @rv.extend_ruby_version
  @ruby_src_dir = nil
end

#refObject



351
352
353
# File 'lib/tebako/options_manager.rb', line 351

def ref
  @ref ||= @options["ref"].nil? ? "tebako-runtime" : @options["ref"].gsub("\\", "/")
end

#relative?(path) ⇒ Boolean

Returns:

  • (Boolean)


347
348
349
# File 'lib/tebako/options_manager.rb', line 347

def relative?(path)
  Pathname.new(path).relative?
end

#remove_glibc_privateObject



355
356
357
358
359
360
361
# File 'lib/tebako/options_manager.rb', line 355

def remove_glibc_private
  @remove_glibc_private ||= if RUBY_PLATFORM.end_with?("linux") || RUBY_PLATFORM.end_with?("linux-gnu")
                              "-DREMOVE_GLIBC_PRIVATE=#{@options["patchelf"] ? "ON" : "OFF"}"
                            else
                              ""
                            end
end

#rootObject



363
364
365
366
367
368
369
370
# File 'lib/tebako/options_manager.rb', line 363

def root
  f_root = @options["root"].nil? ? "" : @options["root"].gsub("\\", "/")
  @root ||= if relative?(f_root)
              File.join(fs_current, f_root)
            else
              File.join(f_root, "")
            end
end

#ruby_src_dirObject



372
373
374
# File 'lib/tebako/options_manager.rb', line 372

def ruby_src_dir
  @ruby_src_dir ||= File.join(deps, "src", "_ruby_#{@ruby_ver}")
end

#runtime_sourceObject

Runtime provenance: "prebuilt" (resolve/download a prebuilt runtime package) or "source" (the Stage-2 source build). Default is "prebuilt" for the bundle/classic/lean/fat modes; other modes always build from source, and --build-runtime forces the source path everywhere it is allowed (back-compat alias for '--runtime source'). The three-part modes (lean/fat) require prebuilt runtime packages: the bootstrap resolves tebako-runtime-ruby releases at run time.



185
186
187
# File 'lib/tebako/options_manager.rb', line 185

def runtime_source
  @runtime_source ||= checked_runtime_source(requested_runtime_source)
end

#sourceObject



376
377
378
379
# File 'lib/tebako/options_manager.rb', line 376

def source
  c_path = Pathname.new(__FILE__).realpath
  @source ||= File.expand_path("../../..", c_path)
end

#stash_dir(rver = nil) ⇒ Object



381
382
383
# File 'lib/tebako/options_manager.rb', line 381

def stash_dir(rver = nil)
  @stash_dir ||= "#{stash_dir_all}_#{rver || @ruby_ver}"
end

#stash_dir_allObject



385
386
387
# File 'lib/tebako/options_manager.rb', line 385

def stash_dir_all
  @stash_dir_all ||= File.join(deps, "stash")
end

#three_part?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/tebako/options_manager.rb', line 170

def three_part?
  THREE_PART_MODES.include?(mode)
end