aibika 1.3.12

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.
data/lib/aibika.rb ADDED
@@ -0,0 +1,675 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'aibika/aibika_builder'
4
+ require_relative 'aibika/cli'
5
+ require_relative 'aibika/host'
6
+ require_relative 'aibika/library_detector'
7
+ require_relative 'aibika/pathname'
8
+ require_relative 'aibika/version'
9
+
10
+ module Aibika
11
+ # Fence against packaging of self (aibika gem) unless implicitly requestd
12
+ # String, NilClass and arrays of any of these.
13
+ def self.fence_self?(name)
14
+ !Aibika.allow_self && name == 'aibika'
15
+ end
16
+
17
+ def self.fence_self_dir?(dir)
18
+ !Aibika.allow_self && dir.start_with?(__dir__)
19
+ end
20
+
21
+ # Type conversion for the Pathname class. Works with Pathname,
22
+ # String, NilClass and arrays of any of these.
23
+ def self.Pathname(obj)
24
+ case obj
25
+ when Pathname
26
+ obj
27
+ when Array
28
+ obj.map { |x| Pathname(x) }
29
+ when String
30
+ Pathname.new(obj)
31
+ when NilClass
32
+ nil
33
+ else
34
+ raise ArgumentError, obj
35
+ end
36
+ end
37
+
38
+ # Sorts and returns an array without duplicates. Works with complex
39
+ # objects (such as Pathname), in contrast to Array#uniq.
40
+ def self.sort_uniq(arr)
41
+ arr.sort.inject([]) { |r, e| r.last == e ? r : r << e }
42
+ end
43
+
44
+ IGNORE_MODULE_NAMES = %r{/(enumerator.so|rational.so|complex.so|fiber.so|thread.rb|ruby2_keywords.rb)$}.freeze
45
+
46
+ GEM_SCRIPT_RE = /\.rbw?$/.freeze
47
+ GEM_EXTRA_RE = %r{(
48
+ # Auxiliary files in the root of the gem
49
+ ^(\./)?(History|Install|Manifest|README|CHANGES|Licen[sc]e|Contributors|ChangeLog|BSD|GPL).*$ |
50
+ # Installation files in the root of the gem
51
+ ^(\./)?(Rakefile|setup.rb|extconf.rb)$ |
52
+ # Documentation/test directories in the root of the gem
53
+ ^(\./)?(doc|ext|examples|test|tests|benchmarks|spec)/ |
54
+ # Directories anywhere
55
+ (^|/)(\.autotest|\.svn|\.cvs|\.git)(/|$) |
56
+ # Unlikely extensions
57
+ \.(rdoc|c|cpp|c\+\+|cxx|h|hxx|hpp|obj|o|a)$/
58
+ )}xi.freeze
59
+
60
+ GEM_NON_FILE_RE = /(#{GEM_EXTRA_RE}|#{GEM_SCRIPT_RE})/.freeze
61
+
62
+ # Alias for the temporary directory where files are extracted.
63
+ TEMPDIR_ROOT = Pathname.new('|')
64
+ # Directory for source files in temporary directory.
65
+ SRCDIR = Pathname.new('src')
66
+ # Directory for Ruby binaries in temporary directory.
67
+ BINDIR = Pathname.new('bin')
68
+ # Directory for GEMHOME files in temporary directory.
69
+ GEMHOMEDIR = Pathname.new('gemhome')
70
+
71
+ @ignore_modules = []
72
+
73
+ @options = {
74
+ lzma_mode: true,
75
+ extra_dlls: [],
76
+ files: [],
77
+ run_script: true,
78
+ add_all_core: false,
79
+ output_override: nil,
80
+ load_autoload: true,
81
+ chdir_first: false,
82
+ force_windows: false,
83
+ force_console: false,
84
+ icon_filename: nil,
85
+ gemfile: nil,
86
+ inno_script: nil,
87
+ quiet: false,
88
+ verbose: false,
89
+ autodll: true,
90
+ show_warnings: true,
91
+ debug: false,
92
+ debug_extract: false,
93
+ arg: [],
94
+ enc: true,
95
+ allow_self: false,
96
+ gem: []
97
+ }
98
+
99
+ @options.each_key { |opt| eval("def self.#{opt}; @options[:#{opt}]; end") }
100
+
101
+ class << self
102
+ attr_reader :lzmapath, :ediconpath, :stubimage, :stubwimage
103
+ end
104
+
105
+ # Returns a binary blob store embedded in the current Ruby script.
106
+ def self.get_next_embedded_image
107
+ DATA.read(DATA.readline.to_i).unpack1('m')
108
+ end
109
+
110
+ def self.save_environment
111
+ @load_path_before = $LOAD_PATH.dup
112
+ @pwd_before = Dir.pwd
113
+ @env_before = {}
114
+ ENV.each { |key, value| @env_before[key] = value }
115
+ end
116
+
117
+ def self.restore_environment
118
+ @env_before.each { |key, value| ENV[key] = value }
119
+ ENV.each_key { |key| ENV.delete(key) unless @env_before.key?(key) }
120
+ Dir.chdir @pwd_before
121
+ end
122
+
123
+ def self.find_stubs
124
+ if defined?(DATA)
125
+ @stubimage = get_next_embedded_image
126
+ @stubwimage = get_next_embedded_image
127
+ lzmaimage = get_next_embedded_image
128
+ @lzmapath = Host.tempdir / 'lzma.exe'
129
+ File.open(@lzmapath, 'wb') { |file| file << lzmaimage }
130
+ ediconimage = get_next_embedded_image
131
+ @ediconpath = Host.tempdir / 'edicon.exe'
132
+ File.open(@ediconpath, 'wb') { |file| file << ediconimage }
133
+ else
134
+ aibikapath = Pathname(File.dirname(__FILE__))
135
+ @stubimage = File.open(aibikapath / '../share/aibika/stub.exe', 'rb', &:read)
136
+ @stubwimage = File.open(aibikapath / '../share/aibika/stubw.exe', 'rb', &:read)
137
+ @lzmapath = (aibikapath / '../share/aibika/lzma.exe').expand
138
+ @ediconpath = (aibikapath / '../share/aibika/edicon.exe').expand
139
+ end
140
+ end
141
+
142
+ def self.init(argv)
143
+ save_environment
144
+ parseargs(argv)
145
+ find_stubs
146
+ @ignore_modules.push(*ObjectSpace.each_object(Module).to_a)
147
+ end
148
+
149
+ # Force loading autoloaded constants. Searches through all modules
150
+ # (and hence classes), and checks their constants for autoloaded
151
+ # ones, then attempts to load them.
152
+ def self.attempt_load_autoload
153
+ modules_checked = {}
154
+ @ignore_modules.each { |m| modules_checked[m] = true }
155
+ loop do
156
+ modules_to_check = []
157
+ ObjectSpace.each_object(Module) do |mod|
158
+ modules_to_check << mod unless modules_checked.include?(mod)
159
+ end
160
+ break if modules_to_check.empty?
161
+
162
+ modules_to_check.each do |mod|
163
+ modules_checked[mod] = true
164
+ mod.constants.each do |const|
165
+ # Module::Config causes warning on Ruby 1.9.3 - prevent autoloading
166
+ next if mod.is_a?(Module) && const == :Config
167
+
168
+ next unless mod.autoload?(const)
169
+
170
+ Aibika.msg "Attempting to trigger autoload of #{mod}::#{const}"
171
+ begin
172
+ mod.const_get(const)
173
+ rescue NameError
174
+ Aibika.warn "#{mod}::#{const} was defined autoloadable, but caused NameError"
175
+ rescue LoadError
176
+ Aibika.warn "#{mod}::#{const} was not loadable"
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ # Guess the load path (from 'paths') that was used to load
184
+ # 'path'. This is primarily relevant on Ruby 1.8 which stores
185
+ # "unqualified" paths in $LOADED_FEATURES.
186
+ def self.find_load_path(loadpaths, feature)
187
+ if feature.absolute?
188
+ # Choose those loadpaths which contain the feature
189
+ candidate_loadpaths = loadpaths.select { |loadpath| feature.subpath?(loadpath.expand) }
190
+ # Guess the require'd feature
191
+ feature_pairs = candidate_loadpaths.map { |loadpath| [loadpath, feature.relative_path_from(loadpath.expand)] }
192
+ # Select the shortest possible require-path (longest load-path)
193
+ if feature_pairs.empty?
194
+ nil
195
+ else
196
+ feature_pairs.min_by { |_loadpath, feature| feature.path.size }[0]
197
+ end
198
+ else
199
+ # Select the loadpaths that contain 'feature' and select the shortest
200
+ candidates = loadpaths.select { |loadpath| feature.expand(loadpath).exist? }
201
+ candidates.max_by { |loadpath| loadpath.path.size }
202
+ end
203
+ end
204
+
205
+ # Find the root of all files specified on the command line and use
206
+ # it as the "src" of the output.
207
+ def self.find_src_root(files)
208
+ src_files = files.map(&:expand)
209
+ src_prefix = src_files.inject(src_files.first.dirname) do |srcroot, path|
210
+ unless path.subpath?(Host.exec_prefix)
211
+ loop do
212
+ relpath = path.relative_path_from(srcroot)
213
+ Aibika.fatal_error 'No common directory contains all specified files' if relpath.absolute?
214
+ break unless relpath.to_s =~ %r{^\.\./}
215
+
216
+ srcroot = srcroot.dirname
217
+ if srcroot == srcroot.dirname
218
+ Aibika.fatal_error "Endless loop detected in find_src_root method. Reducing srcroot --> #{srcroot.dirname}"
219
+ end
220
+ end
221
+ end
222
+ srcroot
223
+ end
224
+ src_files = src_files.map do |file|
225
+ if file.subpath?(src_prefix)
226
+ file.relative_path_from(src_prefix)
227
+ else
228
+ file
229
+ end
230
+ end
231
+ [src_prefix, src_files]
232
+ end
233
+
234
+ # Searches for features that are loaded from gems, then produces a
235
+ # list of files included in those gems' manifests. Also returns a
236
+ # list of original features that are caused gems to be
237
+ # included. Ruby 1.8 provides Gem.loaded_specs to detect gems, but
238
+ # this is empty with Ruby 1.9. So instead, we look for any loaded
239
+ # file from a gem path.
240
+ def self.find_gem_files(features)
241
+ features_from_gems = []
242
+ gems = {}
243
+
244
+ # If a Bundler Gemfile was provided, add all gems it specifies
245
+ if Aibika.gemfile
246
+ Aibika.msg 'Scanning Gemfile'
247
+ # Load Rubygems and Bundler so we can scan the Gemfile
248
+ %w[rubygems bundler].each do |lib|
249
+ require lib
250
+ rescue LoadError
251
+ Aibika.fatal_error "Couldn't scan Gemfile, unable to load #{lib}"
252
+ end
253
+
254
+ ENV['BUNDLE_GEMFILE'] = Aibika.gemfile
255
+ Bundler.load.specs.each do |spec|
256
+ Aibika.verbose_msg "From Gemfile, adding gem #{spec.full_name}"
257
+ gems[spec.name] ||= spec unless fence_self?(spec.name)
258
+ end
259
+
260
+ unless gems.any? { |name, _spec| name == 'bundler' }
261
+ # Bundler itself wasn't added for some reason, let's put it in directly
262
+ Aibika.verbose_msg 'From Gemfile, forcing inclusion of bundler gem itself'
263
+ bundler_spec = Gem.loaded_specs['bundler']
264
+ bundler_spec or Aibika.fatal_error 'Unable to locate bundler gem'
265
+ gems['bundler'] ||= spec
266
+ end
267
+ end
268
+
269
+ if defined?(Gem)
270
+ # Include Gems that are loaded
271
+ Gem.loaded_specs.each { |gemname, spec| gems[gemname] ||= spec unless fence_self?(gemname) }
272
+ # Fall back to gem detection (loaded_specs are not population on
273
+ # all Ruby versions)
274
+ features.each do |feature|
275
+ # Detect load path unless absolute
276
+ unless feature.absolute?
277
+ feature = find_load_path(Pathname($LOAD_PATH), feature)
278
+ next if feature.nil? # Could be enumerator.so
279
+ end
280
+ # Skip if found in known Gem dir
281
+ if gems.find { |_gem, spec| feature.subpath?(spec.gem_dir) }
282
+ features_from_gems << feature
283
+ next
284
+ end
285
+ gempaths = Pathname(Gem.path)
286
+ gempaths.each do |gempath|
287
+ geminstallpath = Pathname(gempath) / 'gems'
288
+ next unless feature.subpath?(geminstallpath)
289
+
290
+ gemlocalpath = feature.relative_path_from(geminstallpath)
291
+ fullgemname = gemlocalpath.path.split('/').first
292
+ gemspecpath = gempath / 'specifications' / "#{fullgemname}.gemspec"
293
+ if (spec = Gem::Specification.load(gemspecpath))
294
+ gems[spec.name] ||= spec
295
+ features_from_gems << feature
296
+ else
297
+ Aibika.warn "Failed to load gemspec for '#{fullgemname}'"
298
+ end
299
+ end
300
+ end
301
+
302
+ gem_files = []
303
+
304
+ gems.each do |gemname, spec|
305
+ next if fence_self?(gemname)
306
+
307
+ if File.exist?(spec.spec_file)
308
+ @gemspecs << Pathname(spec.spec_file)
309
+ else
310
+ spec_name = File.basename(spec.spec_file)
311
+ spec_path = File.dirname(spec.spec_file)
312
+ default_spec_file = "#{spec_path}/default/#{spec_name}"
313
+ if File.exist?(default_spec_file)
314
+ @gemspecs << Pathname(default_spec_file)
315
+ Aibika.msg "Using default specification #{default_spec_file} for gem #{spec.full_name}"
316
+ end
317
+ end
318
+
319
+ # Determine which set of files to include for this particular gem
320
+ include = %i[loaded files]
321
+ Aibika.gem.each do |negate, option, list|
322
+ next unless list.nil? || list.include?(spec.name)
323
+
324
+ case option
325
+ when :minimal
326
+ include = [:loaded]
327
+ when :guess
328
+ include = %i[loaded files]
329
+ when :all
330
+ include = %i[scripts files]
331
+ when :full
332
+ include = %i[scripts files extras]
333
+ when :spec
334
+ include = [:spec]
335
+ when :scripts
336
+ if negate
337
+ include.delete(:scripts)
338
+ else
339
+ include.push(:scripts)
340
+ end
341
+ when :files
342
+ if negate
343
+ include.delete(:files)
344
+ else
345
+ include.push(:files)
346
+ end
347
+ when :extras
348
+ if negate
349
+ include.delete(:extras)
350
+ else
351
+ include.push(:extras)
352
+ end
353
+ end
354
+ end
355
+
356
+ Aibika.msg "Detected gem #{spec.full_name} (#{include.join(', ')})"
357
+
358
+ gem_root = Pathname(spec.gem_dir)
359
+ gem_extension = (gem_root / '..' / '..' / 'extensions').expand
360
+ build_complete = if gem_extension.exist?
361
+ gem_extension.find_all_files(/gem.build_complete/).select do |p|
362
+ p.dirname.basename.to_s == spec.full_name
363
+ end
364
+ end
365
+ gem_root_files = nil
366
+ files = []
367
+
368
+ unless gem_root.directory?
369
+ Aibika.warn "Gem #{spec.full_name} root folder was not found, skipping"
370
+ next
371
+ end
372
+
373
+ # Find the selected files
374
+ include.each do |set|
375
+ case set
376
+ when :spec
377
+ files << Pathname(spec.files)
378
+ when :loaded
379
+ files << features_from_gems.select { |feature| feature.subpath?(gem_root) }
380
+ when :files
381
+ gem_root_files ||= gem_root.find_all_files(//)
382
+ files << gem_root_files.reject { |path| path.relative_path_from(gem_root) =~ GEM_NON_FILE_RE }
383
+ files << build_complete if build_complete
384
+ when :extras
385
+ gem_root_files ||= gem_root.find_all_files(//)
386
+ files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_EXTRA_RE }
387
+ when :scripts
388
+ gem_root_files ||= gem_root.find_all_files(//)
389
+ files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_SCRIPT_RE }
390
+ end
391
+ end
392
+
393
+ files.flatten!
394
+ actual_files = files.select(&:file?)
395
+
396
+ (files - actual_files).each do |missing_file|
397
+ Aibika.warn "#{missing_file} was not found"
398
+ end
399
+
400
+ total_size = actual_files.inject(0) { |size, path| size + path.size }
401
+ Aibika.msg "\t#{actual_files.size} files, #{total_size} bytes"
402
+
403
+ gem_files += actual_files
404
+ end
405
+ gem_files = sort_uniq(gem_files)
406
+ else
407
+ gem_files = []
408
+ end
409
+ features_from_gems -= gem_files
410
+ [gem_files, features_from_gems]
411
+ end
412
+
413
+ def self.build_exe
414
+ all_load_paths = $LOAD_PATH.map { |loadpath| Pathname(loadpath).expand }
415
+ @added_load_paths = ($LOAD_PATH - @load_path_before).map { |loadpath| Pathname(loadpath).expand }
416
+ working_directory = Pathname.pwd.expand
417
+
418
+ restore_environment
419
+
420
+ # If the script was run, then detect the features it used
421
+ if Aibika.run_script && Aibika.load_autoload
422
+ # Attempt to autoload libraries before doing anything else.
423
+ attempt_load_autoload
424
+ end
425
+
426
+ # Reject own aibika itself, store the currently loaded files (before we require rbconfig for
427
+ # our own use).
428
+ features = $LOADED_FEATURES.reject { |feature| fence_self_dir?(feature) }
429
+ features.map! { |feature| Pathname(feature) }
430
+
431
+ # Since https://github.com/rubygems/rubygems/commit/cad4cf16cf8fcc637d9da643ef97cf0be2ed63cb
432
+ # rubygems/core_ext/kernel_require.rb is evaled and thus missing in $LOADED_FEATURES,
433
+ # so we can't find it and need to add it manually
434
+ features.push(Pathname('rubygems/core_ext/kernel_require.rb'))
435
+
436
+ # Find gemspecs to include
437
+ if defined?(Gem)
438
+ loaded_specs = Gem.loaded_specs.reject { |name, _info| fence_self?(name) }
439
+ @gemspecs = loaded_specs.map { |_name, info| Pathname(info.loaded_from) }
440
+ else
441
+ @gemspecs = []
442
+ end
443
+
444
+ require 'rbconfig'
445
+ instsitelibdir = Host.sitelibdir.relative_path_from(Host.exec_prefix)
446
+
447
+ load_path = []
448
+ src_load_path = []
449
+
450
+ # Find gems files and remove them from features
451
+ gem_files, features_from_gems = find_gem_files(features)
452
+ features -= features_from_gems
453
+
454
+ # Find the source root and adjust paths
455
+ src_prefix, = find_src_root(Aibika.files)
456
+ # Include encoding support files
457
+ if Aibika.enc
458
+ all_load_paths.each do |path|
459
+ next unless path.subpath?(Host.exec_prefix)
460
+
461
+ encpath = path / 'enc'
462
+ next unless encpath.exist?
463
+
464
+ encfiles = encpath.find_all_files(/\.so$/)
465
+ size = encfiles.inject(0) { |sum, pn| sum + pn.size }
466
+ Aibika.msg "Including #{encfiles.size} encoding support files (#{size} bytes, use --no-enc to exclude)"
467
+ features.push(*encfiles)
468
+ end
469
+ else
470
+ Aibika.msg 'Not including encoding support files'
471
+ end
472
+
473
+ # Find features and decide where to put them in the temporary
474
+ # directory layout.
475
+ libs = []
476
+ features.each do |feature|
477
+ path = find_load_path(all_load_paths, feature)
478
+ if path.nil? || path.expand == Pathname.pwd
479
+ Aibika.files << feature
480
+ else
481
+ feature = feature.relative_path_from(path.expand) if feature.absolute?
482
+ fullpath = feature.expand(path)
483
+
484
+ if fullpath.subpath?(Host.exec_prefix)
485
+ # Features found in the Ruby installation are put in the
486
+ # temporary Ruby installation.
487
+ libs << [fullpath, fullpath.relative_path_from(Host.exec_prefix)]
488
+ elsif defined?(Gem) && ((gemhome = Gem.path.find { |pth| fullpath.subpath?(pth) }))
489
+ # Features found in any other Gem path (e.g. ~/.gems) is put
490
+ # in a special 'gemhome' folder.
491
+ targetpath = GEMHOMEDIR / fullpath.relative_path_from(Pathname(gemhome))
492
+ libs << [fullpath, targetpath]
493
+ elsif fullpath.subpath?(src_prefix) || path == working_directory
494
+ # Any feature found inside the src_prefix automatically gets
495
+ # added as a source file (to go in 'src').
496
+ Aibika.files << fullpath
497
+ # Add the load path unless it was added by the script while
498
+ # running (or we assume that the script can also set it up
499
+ # correctly when running from the resulting executable).
500
+ src_load_path << path unless @added_load_paths.include?(path)
501
+ elsif @added_load_paths.include?(path)
502
+ # Any feature that exist in a load path added by the script
503
+ # itself is added as a file to go into the 'src' (src_prefix
504
+ # will be adjusted below to point to the common parent).
505
+ Aibika.files << fullpath
506
+ else
507
+ # All other feature that can not be resolved go in the the
508
+ # Ruby sitelibdir. This is automatically in the load path
509
+ # when Ruby starts.
510
+ libs << [fullpath, instsitelibdir / feature]
511
+ end
512
+ end
513
+ end
514
+
515
+ # Recompute the src_prefix. Files may have been added implicitly
516
+ # while scanning through features.
517
+ src_prefix, src_files = find_src_root(Aibika.files)
518
+ Aibika.files.replace(src_files)
519
+
520
+ # Add the load path that are required with the correct path after
521
+ # src_prefix was adjusted.
522
+ load_path += src_load_path.map { |loadpath| TEMPDIR_ROOT / SRCDIR / loadpath.relative_path_from(src_prefix) }
523
+
524
+ # Decide where to put gem files, either the system gem folder, or
525
+ # GEMHOME.
526
+ gem_files.each do |gemfile|
527
+ if gemfile.subpath?(Host.exec_prefix)
528
+ libs << [gemfile, gemfile.relative_path_from(Host.exec_prefix)]
529
+ elsif defined?(Gem) && ((gemhome = Gem.path.find { |pth| gemfile.subpath?(pth) }))
530
+ targetpath = GEMHOMEDIR / gemfile.relative_path_from(Pathname(gemhome))
531
+ libs << [gemfile, targetpath]
532
+ else
533
+ Aibika.msg "Processing #{gemfile}"
534
+ Aibika.msg "Host.exec_prefix #{Host.exec_prefix}"
535
+ Aibika.msg "Gem: #{Gem}" if defined?(Gem)
536
+ Aibika.fatal_error "Don't know where to put gem file #{gemfile}"
537
+ end
538
+ end
539
+
540
+ # If requested, add all ruby standard libraries
541
+ if Aibika.add_all_core
542
+ Aibika.msg 'Will include all ruby core libraries'
543
+ @load_path_before.each do |lp|
544
+ path = Pathname.new(lp)
545
+ next unless path.to_posix =~
546
+ %r{/(ruby/(?:site_ruby/|vendor_ruby/)?[0-9.]+)/?$}i
547
+
548
+ subdir = ::Regexp.last_match(1)
549
+ Dir["#{lp}/**/*"].each do |f|
550
+ fpath = Pathname.new(f)
551
+ next if fpath.directory?
552
+
553
+ tgt = "lib/#{subdir}/#{fpath.relative_path_from(path).to_posix}"
554
+ libs << [f, tgt]
555
+ end
556
+ end
557
+ end
558
+
559
+ # Detect additional DLLs
560
+ dlls = Aibika.autodll ? LibraryDetector.detect_dlls : []
561
+
562
+ # Detect external manifests
563
+ manifests = Host.exec_prefix.find_all_files(/\.manifest$/)
564
+
565
+ executable = nil
566
+ if Aibika.output_override
567
+ executable = Aibika.output_override
568
+ else
569
+ executable = Aibika.files.first.basename.ext('.exe')
570
+ executable.append_to_filename!('-debug') if Aibika.debug
571
+ end
572
+
573
+ windowed = (Aibika.files.first.ext?('.rbw') || Aibika.force_windows) && !Aibika.force_console
574
+
575
+ Aibika.msg "Building #{executable}"
576
+ target_script = nil
577
+ AibikaBuilder.new(executable, windowed) do |sb|
578
+ # Add explicitly mentioned files
579
+ Aibika.msg 'Adding user-supplied source files'
580
+ Aibika.files.each do |file|
581
+ file = src_prefix / file
582
+ target = if file.subpath?(Host.exec_prefix)
583
+ file.relative_path_from(Host.exec_prefix)
584
+ elsif file.subpath?(src_prefix)
585
+ SRCDIR / file.relative_path_from(src_prefix)
586
+ else
587
+ SRCDIR / file.basename
588
+ end
589
+
590
+ target_script ||= target
591
+
592
+ if file.directory?
593
+ sb.ensuremkdir(target)
594
+ else
595
+ begin
596
+ sb.createfile(file, target)
597
+ rescue Errno::ENOENT
598
+ raise unless file =~ IGNORE_MODULE_NAMES
599
+ end
600
+ end
601
+ end
602
+
603
+ # Add the ruby executable and DLL
604
+ rubyexe = if windowed
605
+ Host.rubyw_exe
606
+ else
607
+ Host.ruby_exe
608
+ end
609
+ Aibika.msg "Adding ruby executable #{rubyexe}"
610
+ sb.createfile(Host.bindir / rubyexe, BINDIR / rubyexe)
611
+ sb.createfile(Host.bindir / Host.libruby_so, BINDIR / Host.libruby_so) if Host.libruby_so
612
+
613
+ # Add detected DLLs
614
+ dlls.each do |dll|
615
+ Aibika.msg "Adding detected DLL #{dll}"
616
+ target = if dll.subpath?(Host.exec_prefix)
617
+ dll.relative_path_from(Host.exec_prefix)
618
+ else
619
+ BINDIR / File.basename(dll)
620
+ end
621
+ sb.createfile(dll, target)
622
+ end
623
+
624
+ # Add external manifest files
625
+ manifests.each do |manifest|
626
+ Aibika.msg "Adding external manifest #{manifest}"
627
+ target = manifest.relative_path_from(Host.exec_prefix)
628
+ sb.createfile(manifest, target)
629
+ end
630
+
631
+ # Add extra DLLs specified on the command line
632
+ Aibika.extra_dlls.each do |dll|
633
+ Aibika.msg "Adding supplied DLL #{dll}"
634
+ sb.createfile(Host.bindir / dll, BINDIR / dll)
635
+ end
636
+
637
+ # Add gemspec files
638
+ @gemspecs = sort_uniq(@gemspecs)
639
+ @gemspecs.each do |gemspec|
640
+ if gemspec.subpath?(Host.exec_prefix)
641
+ path = gemspec.relative_path_from(Host.exec_prefix)
642
+ sb.createfile(gemspec, path)
643
+ elsif defined?(Gem) && ((gemhome = Pathname(Gem.path.find { |pth| gemspec.subpath?(pth) })))
644
+ path = GEMHOMEDIR / gemspec.relative_path_from(gemhome)
645
+ sb.createfile(gemspec, path)
646
+ else
647
+ Aibika.fatal_error "Gem spec #{gemspec} does not exist in the Ruby installation. Don't know where to put it."
648
+ end
649
+ end
650
+
651
+ # Add loaded libraries (features, gems)
652
+ Aibika.msg 'Adding library files'
653
+ libs.each do |path, target|
654
+ sb.createfile(path, target)
655
+ end
656
+
657
+ # Set environment variable
658
+ sb.setenv('RUBYOPT', ENV['RUBYOPT'] || '')
659
+ sb.setenv('RUBYLIB', load_path.map(&:to_native).uniq.join(';'))
660
+
661
+ sb.setenv('GEM_PATH', (TEMPDIR_ROOT / GEMHOMEDIR).to_native)
662
+
663
+ # Add the opcode to launch the script
664
+ extra_arg = Aibika.arg.map { |arg| " \"#{arg.gsub('"', '\"')}\"" }.join
665
+ installed_ruby_exe = TEMPDIR_ROOT / BINDIR / rubyexe
666
+ launch_script = (TEMPDIR_ROOT / target_script).to_native
667
+ sb.postcreateprocess(installed_ruby_exe,
668
+ "#{rubyexe} \"#{launch_script}\"#{extra_arg}")
669
+ end
670
+
671
+ return if Aibika.inno_script
672
+
673
+ Aibika.msg "Finished building #{executable} (#{File.size(executable)} bytes)"
674
+ end
675
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+ raise unless defined?(ActiveRecord)
5
+
6
+ puts ActiveRecord::VERSION::STRING
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem 'coderay', git: 'https://github.com/rubychan/coderay.git'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'coderay'
5
+ CodeRay::VERSION
data/samples/mech.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+ require 'ostruct'
6
+ require 'faster_csv'
7
+
8
+ puts 'Hello, World!'