ocran 1.3.15 → 1.3.17

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/bin/ocran DELETED
@@ -1,1317 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # -*- ruby -*-
3
- # encoding: UTF-8
4
-
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