ocran 1.3.15 → 1.3.16

Sign up to get free protection for your applications and to get access to all the features.
data/bin/ocran CHANGED
@@ -1,1317 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- ruby -*-
3
2
  # encoding: UTF-8
4
3
 
5
- module Ocran
6
- # Path handling class. Ruby's Pathname class is not used because it
7
- # is case sensitive and doesn't handle paths with mixed path
8
- # separators.
9
- class Pathname
10
- def Pathname.pwd
11
- Pathname.new(Dir.pwd.encode("UTF-8"))
12
- end
13
-
14
- def Pathname.pathequal(a, b)
15
- a.downcase == b.downcase
16
- end
17
-
18
- def Pathname.glob(pattern, flags = 0)
19
- if block_given?
20
- Dir.glob(pattern, flags) { |s| yield Pathname.new(s) }
21
- else
22
- ary = Dir.glob(pattern, flags)
23
- ary.map! { |s| Pathname.new(s) }
24
- ary
25
- end
26
- end
27
-
28
- attr_reader :path
29
- if File::ALT_SEPARATOR.nil?
30
- File::ALT_SEPARATOR = "\\"
31
- end
32
- SEPARATOR_PAT = /[#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}]/ # }
33
- ABSOLUTE_PAT = /\A([A-Z]:)?#{SEPARATOR_PAT}/i
34
-
35
- def initialize(path)
36
- @path = path.encode("UTF-8")
37
- end
38
-
39
- def to_native
40
- @path.tr File::SEPARATOR, File::ALT_SEPARATOR
41
- end
42
-
43
- def to_posix
44
- @path.tr File::ALT_SEPARATOR, File::SEPARATOR
45
- end
46
-
47
- # Compute the relative path from the 'src' path (directory) to 'tgt'
48
- # (directory or file). Return the absolute path to 'tgt' if it can't
49
- # be reached from 'src'.
50
- def relative_path_from(other)
51
- a = @path.split(SEPARATOR_PAT)
52
- b = other.to_s.split(SEPARATOR_PAT)
53
- while a.first && b.first && Pathname.pathequal(a.first, b.first)
54
- a.shift
55
- b.shift
56
- end
57
- return other if b.first && Pathname.new(b.first).absolute?
58
- b.size.times { a.unshift ".." }
59
- Pathname.new(File.join(*a))
60
- end
61
-
62
- # Determines if 'src' is contained in 'tgt' (i.e. it is a subpath of
63
- # 'tgt'). Both must be absolute paths and not contain '..'
64
- def subpath?(other)
65
- other = Pathname.new(other)
66
- src_normalized = to_posix.downcase
67
- tgt_normalized = other.to_posix.downcase
68
- src_normalized =~ /^#{Regexp.escape tgt_normalized}#{SEPARATOR_PAT}/i
69
- end
70
-
71
- # Join two pathnames together. Returns the right-hand side if it
72
- # is an absolute path. Otherwise, returns the full path of the
73
- # left + right.
74
- def /(other)
75
- other = Pathname.new(other)
76
- if other.absolute?
77
- other
78
- else
79
- Pathname.new(File.join(@path, other.to_s))
80
- end
81
- end
82
-
83
- def append_to_filename!(s)
84
- @path = sub(/(\.[^.]*?|)$/) { s.to_s + $1 }
85
- end
86
-
87
- def sub(*a, &b)
88
- Pathname.new(@path.sub(*a, &b))
89
- end
90
-
91
- def sub_ext(new_ext)
92
- sub(/(\.[^.]*?)?$/, new_ext)
93
- end
94
-
95
- def extname
96
- File.extname(@path)
97
- end
98
-
99
- def ext(new_ext = nil)
100
- if new_ext
101
- sub_ext(new_ext)
102
- else
103
- extname
104
- end
105
- end
106
-
107
- def ext?(expected_ext)
108
- Pathname.pathequal(extname, expected_ext)
109
- end
110
-
111
- def entries
112
- Dir.entries(@path, encoding: "UTF-8").map { |e| self / e }
113
- end
114
-
115
- # Recursively find all files which match a specified regular
116
- # expression.
117
- def find_all_files(re = //)
118
- entries.map do |pn|
119
- if pn.directory?
120
- if pn.basename =~ /^\.\.?$/
121
- []
122
- else
123
- pn.find_all_files(re)
124
- end
125
- elsif pn.file?
126
- if pn.basename =~ re
127
- pn
128
- else
129
- []
130
- end
131
- end
132
- end.flatten
133
- end
134
-
135
- def ==(other); to_posix.downcase == other.to_posix.downcase; end
136
- alias === ==
137
- alias eql? ==
138
- def =~(o); @path =~ o; end
139
- def <=>(other); @path.casecmp(other.to_s); end
140
- def exist?; File.exist?(@path); end
141
- def file?; File.file?(@path); end
142
- def directory?; File.directory?(@path); end
143
- def absolute?; @path =~ ABSOLUTE_PAT; end
144
- def dirname; Pathname.new(File.dirname(@path)); end
145
- def basename; Pathname.new(File.basename(@path)); end
146
-
147
- def expand_path(dir = ".")
148
- Pathname.new(File.expand_path(@path, dir))
149
- end
150
-
151
- def expand(dir = nil); dir ? expand_path(dir) : expand_path; end
152
- def size; File.size(@path); end
153
- def encode(e); to_posix.encode(e); end # called when creating an installer with innosetup
154
-
155
- def binread(*args)
156
- File.binread(@path, *args)
157
- end
158
-
159
- def parent
160
- Pathname.new(File.basename(File.dirname(@path)))
161
- end
162
-
163
- alias to_path to_posix
164
-
165
- alias to_s to_posix
166
- alias to_str to_posix
167
- end
168
-
169
- # Type conversion for the Pathname class. Works with Pathname,
170
- # String, NilClass and arrays of any of these.
171
- def self.Pathname(obj)
172
- case obj
173
- when Pathname
174
- obj
175
- when Array
176
- obj.map { |x| Pathname(x) }
177
- when String
178
- Pathname.new(obj)
179
- when NilClass
180
- nil
181
- else
182
- raise ArgumentError, obj
183
- end
184
- end
185
-
186
- # Variables describing the host's build environment.
187
- module Host
188
- class << self
189
- def exec_prefix
190
- @exec_prefix ||= Ocran.Pathname(RbConfig::CONFIG["exec_prefix"])
191
- end
192
-
193
- def sitelibdir
194
- @sitelibdir ||= Ocran.Pathname(RbConfig::CONFIG["sitelibdir"])
195
- end
196
-
197
- def bindir
198
- @bindir ||= Ocran.Pathname(RbConfig::CONFIG["bindir"])
199
- end
200
-
201
- def libruby_so
202
- @libruby_so ||= Ocran.Pathname(RbConfig::CONFIG["LIBRUBY_SO"])
203
- end
204
-
205
- def exeext
206
- RbConfig::CONFIG["EXEEXT"] || ".exe"
207
- end
208
-
209
- def rubyw_exe
210
- @rubyw_exe ||= (RbConfig::CONFIG["rubyw_install_name"] || "rubyw") + exeext
211
- end
212
-
213
- def ruby_exe
214
- @ruby_exe ||= (RbConfig::CONFIG["ruby_install_name"] || "ruby") + exeext
215
- end
216
-
217
- def tempdir
218
- @tempdir ||= Ocran.Pathname(ENV["TEMP"])
219
- end
220
- end
221
- end
222
-
223
- # Sorts and returns an array without duplicates. Works with complex
224
- # objects (such as Pathname), in contrast to Array#uniq.
225
- def self.sort_uniq(a)
226
- a.sort.inject([]) { |r, e| r.last == e ? r : r << e }
227
- end
228
-
229
- VERSION = "1.3.15"
230
-
231
- IGNORE_MODULE_NAMES = /\/(enumerator.so|rational.so|complex.so|fiber.so|thread.rb|ruby2_keywords.rb)$/
232
-
233
- GEM_SCRIPT_RE = /\.rbw?$/
234
- GEM_EXTRA_RE = %r{(
235
- # Auxiliary files in the root of the gem
236
- ^(\.\/)?(History|Install|Manifest|README|CHANGES|Licen[sc]e|Contributors|ChangeLog|BSD|GPL).*$ |
237
- # Installation files in the root of the gem
238
- ^(\.\/)?(Rakefile|setup.rb|extconf.rb)$ |
239
- # Documentation/test directories in the root of the gem
240
- ^(\.\/)?(doc|ext|examples|test|tests|benchmarks|spec)\/ |
241
- # Directories anywhere
242
- (^|\/)(\.autotest|\.svn|\.cvs|\.git)(\/|$) |
243
- # Unlikely extensions
244
- \.(rdoc|c|cpp|c\+\+|cxx|h|hxx|hpp|obj|o|a)$
245
- )}xi
246
-
247
- GEM_NON_FILE_RE = /(#{GEM_EXTRA_RE}|#{GEM_SCRIPT_RE})/
248
-
249
- # Alias for the temporary directory where files are extracted.
250
- TEMPDIR_ROOT = Pathname.new("|")
251
- # Directory for source files in temporary directory.
252
- SRCDIR = Pathname.new("src")
253
- # Directory for Ruby binaries in temporary directory.
254
- BINDIR = Pathname.new("bin")
255
- # Directory for GEMHOME files in temporary directory.
256
- GEMHOMEDIR = Pathname.new("gemhome")
257
-
258
- IGNORE_MODULES = []
259
-
260
- @options = {
261
- :lzma_mode => true,
262
- :extra_dlls => [],
263
- :files => [],
264
- :run_script => true,
265
- :add_all_core => false,
266
- :output_override => nil,
267
- :load_autoload => true,
268
- :chdir_first => false,
269
- :force_windows => false,
270
- :force_console => false,
271
- :icon_filename => nil,
272
- :rubyopt => nil,
273
- :gemfile => nil,
274
- :inno_script => nil,
275
- :quiet => false,
276
- :verbose => false,
277
- :autodll => true,
278
- :show_warnings => true,
279
- :debug => false,
280
- :debug_extract => false,
281
- :arg => [],
282
- :enc => true,
283
- :gem => [],
284
- }
285
-
286
- @options.each_key { |opt| eval("def self.#{opt}; @options[:#{opt}]; end") }
287
-
288
- class << self
289
- attr_reader :lzmapath
290
- attr_reader :ediconpath
291
- attr_reader :stubimage
292
- attr_reader :stubwimage
293
- end
294
-
295
- def Ocran.msg(s)
296
- puts "=== #{s}" unless Ocran.quiet
297
- end
298
-
299
- def Ocran.verbose_msg(s)
300
- puts s if Ocran.verbose and not Ocran.quiet
301
- end
302
-
303
- def Ocran.warn(s)
304
- msg "WARNING: #{s}" if Ocran.show_warnings
305
- end
306
-
307
- def Ocran.fatal_error(s)
308
- puts "ERROR: #{s}"
309
- exit 1
310
- end
311
-
312
- def Ocran.save_environment
313
- @load_path_before = $LOAD_PATH.dup
314
- @pwd_before = Dir.pwd
315
- @env_before = ENV.to_hash
316
- end
317
-
318
- def Ocran.restore_environment
319
- ENV.clear.update(@env_before)
320
- Dir.chdir @pwd_before
321
- end
322
-
323
- def Ocran.find_stubs
324
- ocranpath = Pathname(File.dirname(__FILE__))
325
- @stubimage = (ocranpath / "../share/ocran/stub.exe").binread
326
- @stubwimage = (ocranpath / "../share/ocran/stubw.exe").binread
327
- @lzmapath = (ocranpath / "../share/ocran/lzma.exe").expand_path
328
- @ediconpath = (ocranpath / "../share/ocran/edicon.exe").expand_path
329
- end
330
-
331
- def Ocran.parseargs(argv)
332
- usage = <<EOF
333
- ocran [options] script.rb
334
-
335
- Ocran options:
336
-
337
- --help Display this information.
338
- --quiet Suppress output while building executable.
339
- --verbose Show extra output while building executable.
340
- --version Display version number and exit.
341
-
342
- Packaging options:
343
-
344
- --dll dllname Include additional DLLs from the Ruby bindir.
345
- --add-all-core Add all core ruby libraries to the executable.
346
- --gemfile <file> Add all gems and dependencies listed in a Bundler Gemfile.
347
- --no-enc Exclude encoding support files
348
-
349
- Gem content detection modes:
350
-
351
- --gem-minimal[=gem1,..] Include only loaded scripts
352
- --gem-guess=[gem1,...] Include loaded scripts & best guess (DEFAULT)
353
- --gem-all[=gem1,..] Include all scripts & files
354
- --gem-full[=gem1,..] Include EVERYTHING
355
- --gem-spec[=gem1,..] Include files in gemspec (Does not work with Rubygems 1.7+)
356
-
357
- minimal: loaded scripts
358
- guess: loaded scripts and other files
359
- all: loaded scripts, other scripts, other files (except extras)
360
- full: Everything found in the gem directory
361
-
362
- --[no-]gem-scripts[=..] Other script files than those loaded
363
- --[no-]gem-files[=..] Other files (e.g. data files)
364
- --[no-]gem-extras[=..] Extra files (README, etc.)
365
-
366
- scripts: .rb/.rbw files
367
- extras: C/C++ sources, object files, test, spec, README
368
- files: all other files
369
-
370
- Auto-detection options:
371
-
372
- --no-dep-run Don't run script.rb to check for dependencies.
373
- --no-autoload Don't load/include script.rb's autoloads.
374
- --no-autodll Disable detection of runtime DLL dependencies.
375
-
376
- Output options:
377
-
378
- --output <file> Name the exe to generate. Defaults to ./<scriptname>.exe.
379
- --no-lzma Disable LZMA compression of the executable.
380
- --innosetup <file> Use given Inno Setup script (.iss) to create an installer.
381
-
382
- Executable options:
383
-
384
- --windows Force Windows application (rubyw.exe)
385
- --console Force console application (ruby.exe)
386
- --chdir-first When exe starts, change working directory to app dir.
387
- --icon <ico> Replace icon with a custom one.
388
- --rubyopt <str> Set the RUBYOPT environment variable when running the executable
389
- --debug Executable will be verbose.
390
- --debug-extract Executable will unpack to local dir and not delete after.
391
- EOF
392
-
393
- while arg = argv.shift
394
- case arg
395
- when /\A--(no-)?lzma\z/
396
- @options[:lzma_mode] = !$1
397
- when /\A--no-dep-run\z/
398
- @options[:run_script] = false
399
- when /\A--add-all-core\z/
400
- @options[:add_all_core] = true
401
- when /\A--output\z/
402
- path = argv.shift
403
- @options[:output_override] = Pathname.new(path) if path
404
- when /\A--dll\z/
405
- path = argv.shift
406
- @options[:extra_dlls] << path if path
407
- when /\A--quiet\z/
408
- @options[:quiet] = true
409
- when /\A--verbose\z/
410
- @options[:verbose] = true
411
- when /\A--windows\z/
412
- @options[:force_windows] = true
413
- when /\A--console\z/
414
- @options[:force_console] = true
415
- when /\A--no-autoload\z/
416
- @options[:load_autoload] = false
417
- when /\A--chdir-first\z/
418
- @options[:chdir_first] = true
419
- when /\A--icon\z/
420
- path = argv.shift
421
- Ocran.fatal_error "Icon file #{path} not found.\n" unless path && File.exist?(path)
422
- @options[:icon_filename] = Pathname.new(path)
423
- when /\A--rubyopt\z/
424
- @options[:rubyopt] = argv.shift
425
- when /\A--gemfile\z/
426
- path = argv.shift
427
- Ocran.fatal_error "Gemfile #{path} not found.\n" unless path && File.exist?(path)
428
- @options[:gemfile] = Pathname.new(path)
429
- when /\A--innosetup\z/
430
- path = argv.shift
431
- Ocran.fatal_error "Inno Script #{path} not found.\n" unless path && File.exist?(path)
432
- @options[:inno_script] = Pathname.new(path)
433
- when /\A--no-autodll\z/
434
- @options[:autodll] = false
435
- when /\A--version\z/
436
- puts "Ocran #{VERSION}"
437
- exit 0
438
- when /\A--no-warnings\z/
439
- @options[:show_warnings] = false
440
- when /\A--debug\z/
441
- @options[:debug] = true
442
- when /\A--debug-extract\z/
443
- @options[:debug_extract] = true
444
- when /\A--\z/
445
- @options[:arg] = ARGV.dup
446
- ARGV.clear
447
- when /\A--(no-)?enc\z/
448
- @options[:enc] = !$1
449
- when /\A--(no-)?gem-(\w+)(?:=(.*))?$/
450
- negate, group, list = $1, $2, $3
451
- @options[:gem] << [negate, group.to_sym, list&.split(",")] if group
452
- when /\A--help\z/, /\A--./
453
- puts usage
454
- exit 0
455
- else
456
- path = arg.dup
457
-
458
- if !File.exist?(path) || Dir.empty?(path)
459
- Ocran.fatal_error "#{path} not found!"
460
- end
461
-
462
- @options[:files] << path
463
- end
464
- end
465
-
466
- if Ocran.debug_extract && Ocran.inno_script
467
- Ocran.fatal_error "The --debug-extract option conflicts with use of Inno Setup"
468
- end
469
-
470
- if Ocran.lzma_mode && Ocran.inno_script
471
- Ocran.fatal_error "LZMA compression must be disabled (--no-lzma) when using Inno Setup"
472
- end
473
-
474
- if !Ocran.chdir_first && Ocran.inno_script
475
- Ocran.fatal_error "Chdir-first mode must be enabled (--chdir-first) when using Inno Setup"
476
- end
477
-
478
- if files.empty?
479
- puts usage
480
- exit 1
481
- end
482
-
483
- @options[:files].map! { |path|
484
- path = path.encode("UTF-8").tr("\\", "/")
485
- if File.directory?(path)
486
- # If a directory is passed, we want all files under that directory
487
- path = "#{path}/**/*"
488
- end
489
- Pathname.glob(path).map!(&:expand_path)
490
- }.flatten!
491
- end
492
-
493
- def Ocran.init(argv)
494
- save_environment
495
- parseargs(argv)
496
- find_stubs
497
- IGNORE_MODULES.push(*ObjectSpace.each_object(Module).to_a)
498
- end
499
-
500
- # Force loading autoloaded constants. Searches through all modules
501
- # (and hence classes), and checks their constants for autoloaded
502
- # ones, then attempts to load them.
503
- def Ocran.attempt_load_autoload
504
- modules_checked = {}
505
- IGNORE_MODULES.each { |m| modules_checked[m] = true }
506
- loop do
507
- modules_to_check = []
508
- ObjectSpace.each_object(Module) do |mod|
509
- modules_to_check << mod unless modules_checked.include?(mod)
510
- end
511
- break if modules_to_check.empty?
512
- modules_to_check.each do |mod|
513
- modules_checked[mod] = true
514
- mod.constants.each do |const|
515
- if mod.autoload?(const)
516
- Ocran.msg "Attempting to trigger autoload of #{mod}::#{const}"
517
- begin
518
- mod.const_get(const)
519
- rescue NameError
520
- Ocran.warn "#{mod}::#{const} was defined autoloadable, but caused NameError"
521
- rescue LoadError
522
- Ocran.warn "#{mod}::#{const} was not loadable"
523
- end
524
- end
525
- end
526
- end
527
- end
528
- end
529
-
530
- # Guess the load path (from 'paths') that was used to load
531
- # 'path'. This is primarily relevant on Ruby 1.8 which stores
532
- # "unqualified" paths in $LOADED_FEATURES.
533
- def Ocran.find_load_path(loadpaths, feature)
534
- if feature.absolute?
535
- # Choose those loadpaths which contain the feature
536
- candidate_loadpaths = loadpaths.select { |loadpath| feature.subpath?(loadpath.expand_path) }
537
- # Guess the require'd feature
538
- feature_pairs = candidate_loadpaths.map { |loadpath| [loadpath, feature.relative_path_from(loadpath.expand_path)] }
539
- # Select the shortest possible require-path (longest load-path)
540
- if feature_pairs.empty?
541
- nil
542
- else
543
- feature_pairs.sort_by { |loadpath, feature| feature.to_s.size }.first[0]
544
- end
545
- else
546
- # Select the loadpaths that contain 'feature' and select the shortest
547
- candidates = loadpaths.select { |loadpath| feature.expand_path(loadpath).exist? }
548
- candidates.sort_by { |loadpath| loadpath.to_s.size }.last
549
- end
550
- end
551
-
552
- # Find the root of all files specified on the command line and use
553
- # it as the "src" of the output.
554
- def Ocran.find_src_root(files)
555
- src_files = files.map { |file| file.expand_path }
556
- src_prefix = src_files.inject(src_files.first.dirname) do |srcroot, path|
557
- if path.subpath?(Host.exec_prefix)
558
- srcroot
559
- else
560
- loop do
561
- relpath = path.relative_path_from(srcroot)
562
- if relpath.absolute?
563
- Ocran.fatal_error "No common directory contains all specified files"
564
- end
565
- if relpath.to_s =~ /^\.\.\//
566
- srcroot = srcroot.dirname
567
- else
568
- break
569
- end
570
- end
571
- srcroot
572
- end
573
- end
574
- src_files = src_files.map do |file|
575
- if file.subpath?(src_prefix)
576
- file.relative_path_from(src_prefix)
577
- else
578
- file
579
- end
580
- end
581
- return src_prefix, src_files
582
- end
583
-
584
- # Searches for features that are loaded from gems, then produces a
585
- # list of files included in those gems' manifests. Also returns a
586
- # list of original features that are caused gems to be
587
- # included. Ruby 1.8 provides Gem.loaded_specs to detect gems, but
588
- # this is empty with Ruby 1.9. So instead, we look for any loaded
589
- # file from a gem path.
590
- def Ocran.find_gem_files(features)
591
- features_from_gems = []
592
- gems = {}
593
-
594
- # If a Bundler Gemfile was provided, add all gems it specifies
595
- if Ocran.gemfile
596
- Ocran.msg "Scanning Gemfile"
597
- # Load Rubygems and Bundler so we can scan the Gemfile
598
- ["rubygems", "bundler"].each do |lib|
599
- begin
600
- require lib
601
- rescue LoadError
602
- Ocran.fatal_error "Couldn't scan Gemfile, unable to load #{lib}"
603
- end
604
- end
605
-
606
- ENV["BUNDLE_GEMFILE"] = Ocran.gemfile.to_s
607
- Bundler.load.specs.each do |spec|
608
- Ocran.verbose_msg "From Gemfile, adding gem #{spec.full_name}"
609
- gems[spec.name] ||= spec
610
- end
611
-
612
- # This code is implemented for compatibility with older Bundler versions (< v1.16.0.pre.1).
613
- unless gems.any? { |name, spec| name == "bundler" }
614
- # Bundler itself wasn't added for some reason, let's put it in directly
615
- Ocran.verbose_msg "From Gemfile, forcing inclusion of bundler gem itself"
616
- bundler_spec = Gem.loaded_specs["bundler"]
617
- bundler_spec or Ocran.fatal_error "Unable to locate bundler gem"
618
- gems["bundler"] ||= bundler_spec
619
- end
620
- end
621
-
622
- if defined?(Gem)
623
- # Include Gems that are loaded
624
- Gem.loaded_specs.each { |gemname, spec| gems[gemname] ||= spec }
625
- # Fall back to gem detection (loaded_specs are not population on
626
- # all Ruby versions)
627
- features.each do |feature|
628
- # Detect load path unless absolute
629
- if not feature.absolute?
630
- feature = find_load_path(Pathname($:), feature)
631
- next if feature.nil? # Could be enumerator.so
632
- end
633
- # Skip if found in known Gem dir
634
- if gems.find { |gem, spec| feature.subpath?(spec.gem_dir) }
635
- features_from_gems << feature
636
- next
637
- end
638
- gempaths = Gem.path
639
- gempaths.each do |gempath|
640
- geminstallpath = Pathname(gempath) / "gems"
641
- if feature.subpath?(geminstallpath)
642
- gemlocalpath = feature.relative_path_from(geminstallpath)
643
- fullgemname = gemlocalpath.to_s.split("/").first
644
- gemspecpath = gempath / "specifications" / "#{fullgemname}.gemspec"
645
- if spec = Gem::Specification.load(gemspecpath)
646
- gems[spec.name] ||= spec
647
- features_from_gems << feature
648
- else
649
- Ocran.warn "Failed to load gemspec for '#{fullgemname}'"
650
- end
651
- end
652
- end
653
- end
654
-
655
- gem_files = []
656
-
657
- gems.each do |gemname, spec|
658
- if File.exist?(spec.spec_file) then
659
- @gemspecs << Pathname(spec.spec_file)
660
- else
661
- spec_name = File.basename(spec.spec_file)
662
- spec_path = File.dirname(spec.spec_file)
663
- default_spec_file = spec_path + "/default/" + spec_name
664
- if File.exist?(default_spec_file) then
665
- @gemspecs << Pathname(default_spec_file)
666
- Ocran.msg "Using default specification #{default_spec_file} for gem #{spec.full_name}"
667
- end
668
- end
669
-
670
- # Determine which set of files to include for this particular gem
671
- include = [:loaded, :files]
672
- Ocran.gem.each do |negate, option, list|
673
- if list.nil? or list.include?(spec.name)
674
- case option
675
- when :minimal
676
- include = [:loaded]
677
- when :guess
678
- include = [:loaded, :files]
679
- when :all
680
- include = [:scripts, :files]
681
- when :full
682
- include = [:scripts, :files, :extras]
683
- when :spec
684
- include = [:spec]
685
- when :scripts
686
- if negate
687
- include.delete(:scripts)
688
- else
689
- include.push(:scripts)
690
- end
691
- when :files
692
- if negate
693
- include.delete(:files)
694
- else
695
- include.push(:files)
696
- end
697
- when :extras
698
- if negate
699
- include.delete(:extras)
700
- else
701
- include.push(:extras)
702
- end
703
- end
704
- end
705
- end
706
-
707
- Ocran.msg "Detected gem #{spec.full_name} (#{include.join(", ")})"
708
-
709
- gem_root = Pathname(spec.gem_dir)
710
- gem_extension = (gem_root / ".." / ".." / "extensions").expand_path
711
- if gem_extension.exist?
712
- build_complete = gem_extension.find_all_files(/gem.build_complete/).select { |p| p.parent.to_s == spec.full_name }
713
- else
714
- build_complete = nil
715
- end
716
- gem_root_files = nil
717
- files = []
718
-
719
- unless gem_root.directory?
720
- Ocran.warn "Gem #{spec.full_name} root folder was not found, skipping"
721
- next
722
- end
723
-
724
- # Find the selected files
725
- include.each do |set|
726
- case set
727
- when :spec
728
- files << Pathname(spec.files)
729
- when :loaded
730
- files << features_from_gems.select { |feature| feature.subpath?(gem_root) }
731
- when :files
732
- gem_root_files ||= gem_root.find_all_files
733
- files << gem_root_files.select { |path| path.relative_path_from(gem_root) !~ GEM_NON_FILE_RE }
734
- files << build_complete if build_complete
735
- when :extras
736
- gem_root_files ||= gem_root.find_all_files
737
- files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_EXTRA_RE }
738
- when :scripts
739
- gem_root_files ||= gem_root.find_all_files
740
- files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_SCRIPT_RE }
741
- end
742
- end
743
-
744
- files.flatten!
745
- actual_files = files.select { |file| file.file? }
746
-
747
- (files - actual_files).each do |missing_file|
748
- Ocran.warn "#{missing_file} was not found"
749
- end
750
-
751
- total_size = actual_files.sum(0, &:size)
752
- Ocran.msg "\t#{actual_files.size} files, #{total_size} bytes"
753
-
754
- gem_files += actual_files
755
- end
756
- gem_files = sort_uniq(gem_files)
757
- else
758
- gem_files = []
759
- end
760
- features_from_gems -= gem_files
761
- return gem_files, features_from_gems
762
- end
763
-
764
- def Ocran.build_exe
765
- all_load_paths = $LOAD_PATH.map { |loadpath| Pathname(loadpath).expand_path }
766
- @added_load_paths = ($LOAD_PATH - @load_path_before).map { |loadpath| Pathname(loadpath).expand_path }
767
- working_directory = Pathname.pwd
768
-
769
- restore_environment
770
-
771
- # If the script was run, then detect the features it used
772
- if Ocran.run_script
773
- # Attempt to autoload libraries before doing anything else.
774
- attempt_load_autoload if Ocran.load_autoload
775
- end
776
-
777
- # Store the currently loaded files (before we require rbconfig for
778
- # our own use).
779
- features = $LOADED_FEATURES.map { |feature| Pathname(feature) }
780
-
781
- # Since https://github.com/rubygems/rubygems/commit/cad4cf16cf8fcc637d9da643ef97cf0be2ed63cb
782
- # rubygems/core_ext/kernel_require.rb is evaled and thus missing in $LOADED_FEATURES, so we can't find it and need to add it manually
783
- features.push(Pathname("rubygems/core_ext/kernel_require.rb"))
784
-
785
- # Find gemspecs to include
786
- if defined?(Gem)
787
- @gemspecs = Gem.loaded_specs.map { |name, info| Pathname(info.loaded_from) }
788
- else
789
- @gemspecs = []
790
- end
791
-
792
- require "rbconfig"
793
- instsitelibdir = Host.sitelibdir.relative_path_from(Host.exec_prefix)
794
-
795
- load_path = []
796
- src_load_path = []
797
-
798
- # Find gems files and remove them from features
799
- gem_files, features_from_gems = find_gem_files(features)
800
- features -= features_from_gems
801
-
802
- # Find the source root and adjust paths
803
- src_prefix, src_files = find_src_root(Ocran.files)
804
-
805
- # Include encoding support files
806
- if Ocran.enc
807
- all_load_paths.each do |path|
808
- if path.subpath?(Host.exec_prefix)
809
- encpath = path / "enc"
810
- if encpath.exist?
811
- encfiles = encpath.find_all_files(/\.so$/)
812
- size = encfiles.sum(0, &:size)
813
- Ocran.msg "Including #{encfiles.size} encoding support files (#{size} bytes, use --no-enc to exclude)"
814
- features.push(*encfiles)
815
- end
816
- end
817
- end
818
- else
819
- Ocran.msg "Not including encoding support files"
820
- end
821
-
822
- # Find features and decide where to put them in the temporary
823
- # directory layout.
824
- libs = []
825
- features.each do |feature|
826
- path = find_load_path(all_load_paths, feature)
827
- if path.nil? || path.expand_path == Pathname.pwd
828
- Ocran.files << feature
829
- else
830
- if feature.absolute?
831
- feature = feature.relative_path_from(path.expand_path)
832
- end
833
- fullpath = feature.expand_path(path)
834
-
835
- if fullpath.subpath?(Host.exec_prefix)
836
- # Features found in the Ruby installation are put in the
837
- # temporary Ruby installation.
838
- libs << [fullpath, fullpath.relative_path_from(Host.exec_prefix)]
839
- elsif defined?(Gem) and gemhome = Gem.path.find { |pth| fullpath.subpath?(pth) }
840
- # Features found in any other Gem path (e.g. ~/.gems) is put
841
- # in a special 'gemhome' folder.
842
- targetpath = GEMHOMEDIR / fullpath.relative_path_from(Pathname(gemhome))
843
- libs << [fullpath, targetpath]
844
- elsif fullpath.subpath?(src_prefix) || path == working_directory
845
- # Any feature found inside the src_prefix automatically gets
846
- # added as a source file (to go in 'src').
847
- Ocran.files << fullpath
848
- # Add the load path unless it was added by the script while
849
- # running (or we assume that the script can also set it up
850
- # correctly when running from the resulting executable).
851
- src_load_path << path unless @added_load_paths.include?(path)
852
- elsif @added_load_paths.include?(path)
853
- # Any feature that exist in a load path added by the script
854
- # itself is added as a file to go into the 'src' (src_prefix
855
- # will be adjusted below to point to the common parent).
856
- Ocran.files << fullpath
857
- else
858
- # All other feature that can not be resolved go in the the
859
- # Ruby sitelibdir. This is automatically in the load path
860
- # when Ruby starts.
861
- libs << [fullpath, instsitelibdir / feature]
862
- end
863
- end
864
- end
865
-
866
- # Recompute the src_prefix. Files may have been added implicitly
867
- # while scanning through features.
868
- src_prefix, src_files = find_src_root(Ocran.files)
869
- Ocran.files.replace(src_files)
870
-
871
- # Add the load path that are required with the correct path after
872
- # src_prefix was adjusted.
873
- load_path += src_load_path.map { |loadpath| TEMPDIR_ROOT / SRCDIR / loadpath.relative_path_from(src_prefix) }
874
-
875
- # Decide where to put gem files, either the system gem folder, or
876
- # GEMHOME.
877
- gem_files.each do |gemfile|
878
- if gemfile.subpath?(Host.exec_prefix)
879
- libs << [gemfile, gemfile.relative_path_from(Host.exec_prefix)]
880
- elsif defined?(Gem) and gemhome = Gem.path.find { |pth| gemfile.subpath?(pth) }
881
- targetpath = GEMHOMEDIR / gemfile.relative_path_from(Pathname(gemhome))
882
- libs << [gemfile, targetpath]
883
- else
884
- Ocran.fatal_error "Don't know where to put gemfile #{gemfile}"
885
- end
886
- end
887
-
888
- # If requested, add all ruby standard libraries
889
- if Ocran.add_all_core
890
- Ocran.msg "Will include all ruby core libraries"
891
- @load_path_before.each do |lp|
892
- path = Pathname.new(lp)
893
- next unless path.to_posix =~
894
- /\/(ruby\/(?:site_ruby\/|vendor_ruby\/)?[0-9.]+)\/?$/i
895
- subdir = $1
896
- Pathname.glob("#{lp}/**/*").each do |fpath|
897
- next if fpath.directory?
898
- tgt = "lib/#{subdir}/#{fpath.relative_path_from(path).to_posix}"
899
- libs << [fpath, tgt]
900
- end
901
- end
902
- end
903
-
904
- # Detect additional DLLs
905
- dlls = Ocran.autodll ? LibraryDetector.detect_dlls : []
906
-
907
- # Detect external manifests
908
- # For RubyInstaller environments supporting Ruby 2.4 and above,
909
- # a manifest file is required.
910
- if (manifest = Host.exec_prefix / "bin/ruby_builtin_dlls/ruby_builtin_dlls.manifest").exist?
911
- manifests = [manifest]
912
- else
913
- manifests = []
914
- end
915
-
916
- executable = nil
917
- if Ocran.output_override
918
- executable = Ocran.output_override
919
- else
920
- executable = Ocran.files.first.basename.sub_ext(".exe")
921
- executable.append_to_filename!("-debug") if Ocran.debug
922
- end
923
-
924
- windowed = (Ocran.files.first.ext?(".rbw") || Ocran.force_windows) && !Ocran.force_console
925
-
926
- Ocran.msg "Building #{executable}"
927
- target_script = nil
928
- OcranBuilder.new(executable, windowed) do |sb|
929
- # Add explicitly mentioned files
930
- Ocran.msg "Adding user-supplied source files"
931
- Ocran.files.each do |file|
932
- file = src_prefix / file
933
- if file.subpath?(Host.exec_prefix)
934
- target = file.relative_path_from(Host.exec_prefix)
935
- elsif file.subpath?(src_prefix)
936
- target = SRCDIR / file.relative_path_from(src_prefix)
937
- else
938
- target = SRCDIR / file.basename
939
- end
940
-
941
- target_script ||= target
942
-
943
- if file.directory?
944
- sb.ensuremkdir(target)
945
- else
946
- begin
947
- sb.createfile(file, target)
948
- rescue Errno::ENOENT
949
- raise unless file =~ IGNORE_MODULE_NAMES
950
- end
951
- end
952
- end
953
-
954
- # Add the ruby executable and DLL
955
- if windowed
956
- rubyexe = Host.rubyw_exe
957
- else
958
- rubyexe = Host.ruby_exe
959
- end
960
- Ocran.msg "Adding ruby executable #{rubyexe}"
961
- sb.createfile(Host.bindir / rubyexe, BINDIR / rubyexe)
962
- if Host.libruby_so
963
- sb.createfile(Host.bindir / Host.libruby_so, BINDIR / Host.libruby_so)
964
- end
965
-
966
- # Add detected DLLs
967
- dlls.each do |dll|
968
- Ocran.msg "Adding detected DLL #{dll}"
969
- if dll.subpath?(Host.exec_prefix)
970
- target = dll.relative_path_from(Host.exec_prefix)
971
- else
972
- target = BINDIR / File.basename(dll)
973
- end
974
- sb.createfile(dll, target)
975
- end
976
-
977
- # Add external manifest files
978
- manifests.each do |manifest|
979
- Ocran.msg "Adding external manifest #{manifest}"
980
- target = manifest.relative_path_from(Host.exec_prefix)
981
- sb.createfile(manifest, target)
982
- end
983
-
984
- # Add extra DLLs specified on the command line
985
- Ocran.extra_dlls.each do |dll|
986
- Ocran.msg "Adding supplied DLL #{dll}"
987
- sb.createfile(Host.bindir / dll, BINDIR / dll)
988
- end
989
-
990
- # Add gemspec files
991
- @gemspecs = sort_uniq(@gemspecs)
992
- @gemspecs.each do |gemspec|
993
- if gemspec.subpath?(Host.exec_prefix)
994
- path = gemspec.relative_path_from(Host.exec_prefix)
995
- sb.createfile(gemspec, path)
996
- elsif defined?(Gem) and gemhome = Gem.path.find { |pth| gemspec.subpath?(pth) }
997
- path = GEMHOMEDIR / gemspec.relative_path_from(Pathname(gemhome))
998
- sb.createfile(gemspec, path)
999
- else
1000
- Ocran.fatal_error "Gem spec #{gemspec} does not exist in the Ruby installation. Don't know where to put it."
1001
- end
1002
- end
1003
-
1004
- # Add loaded libraries (features, gems)
1005
- Ocran.msg "Adding library files"
1006
- libs.each do |path, target|
1007
- sb.createfile(path, target)
1008
- end
1009
-
1010
- # Workaround: RubyInstaller cannot find the msys folder if ../msys64/usr/bin/msys-2.0.dll is not present (since RubyInstaller-2.4.1 rubyinstaller 2 issue 23)
1011
- # Add an empty file to /msys64/usr/bin/msys-2.0.dll if the dll was not required otherwise
1012
- unless sb.files.keys.any? { |entry| entry.to_s.include?("msys-2.0.dll") }
1013
- sb.createfile(Pathname(File.dirname(__FILE__)) / "../share/ocran/empty-msys-2.0.dll".to_s, 'msys64/usr/bin/msys-2.0.dll')
1014
- end
1015
-
1016
- # Set environment variable
1017
- sb.setenv("RUBYOPT", Ocran.rubyopt || ENV["RUBYOPT"] || "")
1018
- sb.setenv("RUBYLIB", load_path.map { |path| path.to_native }.uniq.join(";"))
1019
-
1020
- sb.setenv("GEM_PATH", (TEMPDIR_ROOT / GEMHOMEDIR).to_native)
1021
-
1022
- # Add the opcode to launch the script
1023
- extra_arg = Ocran.arg.map { |arg| ' "' + arg.gsub("\"", "\\\"") + '"' }.join
1024
- installed_ruby_exe = TEMPDIR_ROOT / BINDIR / rubyexe
1025
- launch_script = (TEMPDIR_ROOT / target_script).to_native
1026
- sb.postcreateprocess(installed_ruby_exe,
1027
- "#{rubyexe} \"#{launch_script}\"#{extra_arg}")
1028
- end
1029
-
1030
- unless Ocran.inno_script
1031
- Ocran.msg "Finished building #{executable} (#{File.size(executable)} bytes)"
1032
- end
1033
- end
1034
-
1035
- module LibraryDetector
1036
- # Windows API functions for handling files may return long paths,
1037
- # with a maximum character limit of 32,767.
1038
- # "\\?\" prefix(4 characters) + long path(32762 characters) + NULL = 32767 characters
1039
- # https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
1040
- MAX_PATH = 32767
1041
-
1042
- # The byte size of the buffer given as an argument to the EnumProcessModules function.
1043
- # This buffer is used to store the handles of the loaded modules.
1044
- # If the buffer size is smaller than the number of loaded modules,
1045
- # it will automatically increase the buffer size and call the EnumProcessModules function again.
1046
- # Increasing the initial buffer size can reduce the number of iterations required.
1047
- # https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-modules-for-a-process
1048
- DEFAULT_HMODULE_BUFFER_SIZE = 1024
1049
-
1050
- def LibraryDetector.init_fiddle
1051
- require "fiddle/import"
1052
- require "fiddle/types"
1053
-
1054
- extend Fiddle::Importer
1055
- dlload "kernel32.dll", "psapi.dll"
1056
-
1057
- include Fiddle::Win32Types
1058
- # https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
1059
- typealias "HINSTANCE", "HANDLE" # for Ruby2.6 only
1060
- typealias "HMODULE", "HINSTANCE"
1061
- typealias "LPDWORD", "PDWORD"
1062
- typealias "LPWSTR", "char*"
1063
-
1064
- extern "BOOL EnumProcessModules(HANDLE, HMODULE*, DWORD, LPDWORD)"
1065
- extern "DWORD GetModuleFileNameW(HMODULE, LPWSTR, DWORD)"
1066
- extern "HANDLE GetCurrentProcess()"
1067
- extern "DWORD GetLastError()"
1068
- end
1069
-
1070
- def LibraryDetector.loaded_dlls
1071
- init_fiddle
1072
-
1073
- dword = "L" # A DWORD is a 32-bit unsigned integer.
1074
- bytes_needed = [0].pack(dword)
1075
- bytes = DEFAULT_HMODULE_BUFFER_SIZE
1076
- process_handle = GetCurrentProcess()
1077
- handles = while true
1078
- buffer = "\x00" * bytes
1079
- if EnumProcessModules(process_handle, buffer, buffer.bytesize, bytes_needed) == 0
1080
- Ocran.fatal_error "LibraryDetector: EnumProcessModules failed with error code %#010x" % GetLastError()
1081
- end
1082
- bytes = bytes_needed.unpack1(dword)
1083
- if bytes <= buffer.bytesize
1084
- break buffer.unpack("J#{bytes / Fiddle::SIZEOF_VOIDP}")
1085
- end
1086
- end
1087
- str = "\x00".encode("UTF-16LE") * MAX_PATH
1088
- handles.map do |handle|
1089
- length = GetModuleFileNameW(handle, str, str.bytesize)
1090
- if length == 0
1091
- Ocran.fatal_error "LibraryDetector: GetModuleFileNameW failed with error code %#010x" % GetLastError()
1092
- end
1093
- Ocran.Pathname(str[0, length])
1094
- end
1095
- end
1096
-
1097
- def LibraryDetector.detect_dlls
1098
- loaded = loaded_dlls
1099
- exec_prefix = Host.exec_prefix
1100
- loaded.select { |path| path.subpath?(exec_prefix) && path.basename.ext?(".dll") && path.basename != Host.libruby_so }
1101
- end
1102
- end
1103
-
1104
- # Utility class that produces the actual executable. Opcodes
1105
- # (createfile, mkdir etc) are added by invoking methods on an
1106
- # instance of OcranBuilder.
1107
- class OcranBuilder
1108
- Signature = [0x41, 0xb6, 0xba, 0x4e]
1109
- OP_END = 0
1110
- OP_CREATE_DIRECTORY = 1
1111
- OP_CREATE_FILE = 2
1112
- OP_CREATE_PROCESS = 3
1113
- OP_DECOMPRESS_LZMA = 4
1114
- OP_SETENV = 5
1115
- OP_POST_CREATE_PROCESS = 6
1116
- OP_ENABLE_DEBUG_MODE = 7
1117
- OP_CREATE_INST_DIRECTORY = 8
1118
-
1119
- attr_reader :files
1120
-
1121
- def initialize(path, windowed)
1122
- @paths = {}
1123
- @files = {}
1124
- File.open(path, "wb") do |ocranfile|
1125
- image = nil
1126
- if windowed
1127
- image = Ocran.stubwimage
1128
- else
1129
- image = Ocran.stubimage
1130
- end
1131
-
1132
- unless image
1133
- Ocran.fatal_error "Stub image not available"
1134
- end
1135
- ocranfile.write(image)
1136
- end
1137
-
1138
- if Ocran.icon_filename
1139
- system Ocran.ediconpath.to_s, path.to_s, Ocran.icon_filename.to_s
1140
- end
1141
-
1142
- opcode_offset = File.size(path)
1143
-
1144
- File.open(path, "ab") do |ocranfile|
1145
- tmpinpath = "tmpin"
1146
-
1147
- if Ocran.lzma_mode
1148
- @of = File.open(tmpinpath, "wb")
1149
- else
1150
- @of = ocranfile
1151
- end
1152
-
1153
- if Ocran.debug
1154
- Ocran.msg("Enabling debug mode in executable")
1155
- ocranfile.write([OP_ENABLE_DEBUG_MODE].pack("V"))
1156
- end
1157
-
1158
- createinstdir Ocran.debug_extract, !Ocran.debug_extract, Ocran.chdir_first
1159
-
1160
- yield(self)
1161
-
1162
- @of.close if Ocran.lzma_mode
1163
-
1164
- if Ocran.lzma_mode and not Ocran.inno_script
1165
- tmpoutpath = "tmpout"
1166
- begin
1167
- data_size = File.size(tmpinpath)
1168
- Ocran.msg "Compressing #{data_size} bytes"
1169
- system(Ocran.lzmapath.to_s, "e", tmpinpath, tmpoutpath) or fail
1170
- compressed_data_size = File.size?(tmpoutpath)
1171
- ocranfile.write([OP_DECOMPRESS_LZMA, compressed_data_size].pack("VV"))
1172
- IO.copy_stream(tmpoutpath, ocranfile)
1173
- ensure
1174
- File.unlink(@of.path) if File.exist?(@of.path)
1175
- File.unlink(tmpoutpath) if File.exist?(tmpoutpath)
1176
- end
1177
- end
1178
-
1179
- ocranfile.write([OP_END].pack("V"))
1180
- ocranfile.write([opcode_offset].pack("V")) # Pointer to start of opcodes
1181
- ocranfile.write(Signature.pack("C*"))
1182
- end
1183
-
1184
- if Ocran.inno_script
1185
- begin
1186
- iss = File.read(Ocran.inno_script) + "\n\n"
1187
-
1188
- iss << "[Dirs]\n"
1189
- @paths.each_key do |p|
1190
- iss << "Name: \"{app}/#{p}\"\n"
1191
- end
1192
- iss << "\n"
1193
-
1194
- iss << "[Files]\n"
1195
- path_escaped = path.to_s.gsub('"', '""')
1196
- iss << "Source: \"#{path_escaped}\"; DestDir: \"{app}\"\n"
1197
- @files.each do |tgt, src|
1198
- src_escaped = src.to_s.gsub('"', '""')
1199
- target_dir_escaped = Pathname.new(tgt).dirname.to_s.gsub('"', '""')
1200
- iss << "Source: \"#{src_escaped}\"; DestDir: \"{app}/#{target_dir_escaped}\"\n" unless src_escaped =~ IGNORE_MODULE_NAMES
1201
- end
1202
- iss << "\n"
1203
-
1204
- Ocran.verbose_msg "### INNOSETUP SCRIPT ###\n\n#{iss}\n\n"
1205
-
1206
- f = File.open("ocrantemp.iss", "w")
1207
- f.write(iss)
1208
- f.close()
1209
-
1210
- iscc_cmd = ["iscc"]
1211
- iscc_cmd << "/Q" unless Ocran.verbose
1212
- iscc_cmd << "ocrantemp.iss"
1213
- Ocran.msg "Running InnoSetup compiler ISCC"
1214
- result = system(*iscc_cmd)
1215
- if not result
1216
- case $?.exitstatus
1217
- when 0 then raise RuntimeError.new("ISCC reported success, but system reported error?")
1218
- when 1 then raise RuntimeError.new("ISCC reports invalid command line parameters")
1219
- when 2 then raise RuntimeError.new("ISCC reports that compilation failed")
1220
- else raise RuntimeError.new("ISCC failed to run. Is the InnoSetup directory in your PATH?")
1221
- end
1222
- end
1223
- rescue Exception => e
1224
- Ocran.fatal_error("InnoSetup installer creation failed: #{e.message}")
1225
- ensure
1226
- File.unlink("ocrantemp.iss") if File.exist?("ocrantemp.iss")
1227
- File.unlink(path) if File.exist?(path)
1228
- end
1229
- end
1230
- end
1231
-
1232
- def mkdir(path)
1233
- return if @paths[path.to_s.downcase]
1234
- @paths[path.to_posix.downcase] = true
1235
- Ocran.verbose_msg "m #{showtempdir path}"
1236
- unless Ocran.inno_script # The directory will be created by InnoSetup with a [Dirs] statement
1237
- @of << [OP_CREATE_DIRECTORY, path.to_native].pack("VZ*")
1238
- end
1239
- end
1240
-
1241
- def ensuremkdir(tgt)
1242
- tgt = Ocran.Pathname(tgt)
1243
- return if tgt.to_s == "."
1244
- if not @paths[tgt.to_posix.downcase]
1245
- ensuremkdir(tgt.dirname)
1246
- mkdir(tgt)
1247
- end
1248
- end
1249
-
1250
- def createinstdir(next_to_exe = false, delete_after = false, chdir_before = false)
1251
- unless Ocran.inno_script # Creation of installation directory will be handled by InnoSetup
1252
- @of << [OP_CREATE_INST_DIRECTORY, next_to_exe ? 1 : 0, delete_after ? 1 : 0, chdir_before ? 1 : 0].pack("VVVV")
1253
- end
1254
- end
1255
-
1256
- def createfile(src, tgt)
1257
- return if @files[tgt]
1258
- @files[tgt] = src
1259
- src, tgt = Ocran.Pathname(src), Ocran.Pathname(tgt)
1260
- ensuremkdir(tgt.dirname)
1261
- str = src.binread
1262
- Ocran.verbose_msg "a #{showtempdir tgt}"
1263
- unless Ocran.inno_script # InnoSetup will install the file with a [Files] statement
1264
- @of << [OP_CREATE_FILE, tgt.to_native, str.size].pack("VZ*V")
1265
- @of << str
1266
- end
1267
- end
1268
-
1269
- def hasFile?(src)
1270
- end
1271
-
1272
- def createprocess(image, cmdline)
1273
- Ocran.verbose_msg "l #{showtempdir image} #{showtempdir cmdline}"
1274
- @of << [OP_CREATE_PROCESS, image.to_native, cmdline].pack("VZ*Z*")
1275
- end
1276
-
1277
- def postcreateprocess(image, cmdline)
1278
- Ocran.verbose_msg "p #{showtempdir image} #{showtempdir cmdline}"
1279
- @of << [OP_POST_CREATE_PROCESS, image.to_native, cmdline].pack("VZ*Z*")
1280
- end
1281
-
1282
- def setenv(name, value)
1283
- Ocran.verbose_msg "e #{name} #{showtempdir value}"
1284
- @of << [OP_SETENV, name, value].pack("VZ*Z*")
1285
- end
1286
-
1287
- def close
1288
- @of.close
1289
- end
1290
-
1291
- def showtempdir(x)
1292
- x.to_s.gsub(TEMPDIR_ROOT.to_s, "<tempdir>")
1293
- end
1294
- end # class OcranBuilder
1295
- end # module Ocran
1296
-
1297
- if File.basename(__FILE__) == File.basename($0)
1298
- Ocran.init(ARGV)
1299
- ARGV.replace(Ocran.arg)
1300
-
1301
- if not Ocran.files.first.exist?
1302
- Ocran.fatal_error "#{Ocran.files[0]} was not found!"
1303
- end
1304
-
1305
- at_exit do
1306
- if $!.nil? or $!.kind_of?(SystemExit)
1307
- Ocran.build_exe
1308
- exit 0
1309
- end
1310
- end
1311
-
1312
- if Ocran.run_script
1313
- Ocran.msg "Loading script to check dependencies"
1314
- $0 = Ocran.files.first.to_s
1315
- load Ocran.files.first
1316
- end
1317
- end
4
+ load File.expand_path("../lib/ocran/runner.rb", __dir__)
5
+ load Ocran::Runner.new.run