aibika 1.3.12

Sign up to get free protection for your applications and to get access to all the features.
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!'