neri 0.1.6 → 0.1.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 174c9950502ddeda2273e775f0744d3e77f06860
4
- data.tar.gz: 7778da03d718d974c48e2926996c5ffa264b3366
3
+ metadata.gz: e699a30dc268671099543044580f9e72fa8c4877
4
+ data.tar.gz: 666dc483a8e9fe3e0d960266955aeec0e5b82f5b
5
5
  SHA512:
6
- metadata.gz: a6790276ff5d836d9ac00f1ccdc09ae307456369e4b169596c32479df41c444000962e0cb178876253b47fd0a2e4ce189a2b0bcf19ab0d862366f885ff0dc7c7
7
- data.tar.gz: ec2b20a88f243406faa83933e19edf44a0f2676857bc0ba69c2669d4549d87a32f5472ce0b38270c76fbe269bd01f0c3d8022b3f4ced12d7443ab41429a17e2d
6
+ metadata.gz: 4efcd72f33e42e1fcbd77abdc5ebd3ff33a087cec3e2298a59acba57169a1365952aeed7e0dc2c97e98bfeb04b6b3658d6f31d7607264b72cd23be49b266f599
7
+ data.tar.gz: e8b1d42824577cc8642d8b956345f8404c3ffef4a632c685e863e39e7c508493a225592cbcd2fe3bbdd63ad34b733b0bd71a4fc744ee444d2917d2497b29d7bc
data/README.ja.md CHANGED
@@ -6,6 +6,7 @@ Neri は、Ruby スクリプトを Ruby 未インストール環境向けに配
6
6
 
7
7
  - OCRA に比べての長所
8
8
  - 展開しない分、起動が速い。
9
+ - 実行ファイルを複数作りたいとき、OCRA ではサイズの大きな実行ファイルを複数生成することになってしまうが、Neri ではシステムファイルを共有できるので、全体のサイズが大きくならずに済む。
9
10
  - OCRA には「日本語を含むユーザー名の環境では起動できない」という問題があるが、Neri にはない。
10
11
  - ただし Ruby のバージョンによっては、日本語を含むパス上では起動できない。(OCRA も同様。)
11
12
  - OCRA に比べての短所
@@ -108,7 +109,7 @@ Neri はデフォルトでは、enc フォルダ内の文字コードライブ
108
109
 
109
110
  #### Bat To Exe Converter
110
111
 
111
- Neri は単独では bat ファイルを作成するのみですが、Bat To Exe Converter があれば exe ファイルを作成できます。
112
+ Neri は単独では bat ファイルを作成するのみですが、Bat To Exe Converter(ver.3) があれば exe ファイルを作成できます。
112
113
 
113
114
  <dl>
114
115
  <dt>--no-exe</dt>
data/lib/neri/build.rb CHANGED
@@ -1,718 +1,718 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- require "neri"
5
-
6
- module Neri
7
- @data_files = []
8
- @system_files = []
9
-
10
- @options = {
11
- quiet: false,
12
- verbose: false,
13
-
14
- dlls: [],
15
- libs: [],
16
- gems: [],
17
- encoding: "*",
18
-
19
- enable_gems: false,
20
- enable_did_you_mean: false,
21
- chdir_first: false,
22
- pause_last: nil,
23
- pause_text: nil,
24
-
25
- output_dir: nil,
26
- system_dir: "system",
27
-
28
- data_file: nil,
29
- encryption_key: nil,
30
-
31
- no_exe: false,
32
- b2ec_path: "Bat_To_Exe_Converter.exe",
33
- b2ec: {
34
- icon: "#{File.expand_path(File.dirname(__FILE__) + '/../../share/default.ico')}",
35
- invisible: nil,
36
- x64: nil,
37
- uac_admin: nil,
38
- fileversion: nil,
39
- productversion: nil,
40
- productname: nil,
41
- originalfilename: nil,
42
- internalname: nil,
43
- description: nil,
44
- company: nil,
45
- trademarks: nil,
46
- copyright: nil,
47
- privatebuild: nil,
48
- specialbuild: nil,
49
- comments: nil
50
- },
51
-
52
- use_upx: false,
53
- upx_path: "upx.exe",
54
- upx_targets: ["bin/**/*.dll"],
55
- upx_options: "",
56
-
57
- zipfile: nil,
58
- sevenzip_path: "7z.exe",
59
-
60
- inno_script: nil,
61
- iscc_path: "iscc",
62
- }
63
- @rubyopt = ENV["RUBYOPT"].to_s
64
- @encryption_key = nil
65
-
66
- @use_dxruby = false
67
- @use_dxruby_tiled = false
68
- @use_ayame = false
69
-
70
- class << self
71
-
72
- attr_reader :options
73
-
74
- def relative_path(path, basedir=rubydir, prepath = "")
75
- basedir.concat(File::SEPARATOR) unless basedir.end_with?(File::SEPARATOR)
76
- return path.start_with?(basedir) ? path.sub(basedir, prepath) : path
77
- end
78
-
79
- def to_winpath(path)
80
- return File::ALT_SEPARATOR ? path.tr(File::SEPARATOR, File::ALT_SEPARATOR) : path
81
- end
82
-
83
- def bindir( ); RbConfig::CONFIG["bindir"] || File.join(rubydir, "bin"); end
84
- def rubydir( ); RbConfig::TOPDIR; end
85
- def rubyexe( ); RbConfig.ruby; end
86
- def batchfile(); File.join(options[:output_dir], "#{File.basename(@data_files.first, ".*")}.bat"); end
87
- def datafile( ); File.join(options[:output_dir], options[:system_dir], options[:data_file]); end
88
-
89
- # --help
90
- def output_help
91
- puts <<-EOF
92
- usage: neri [options] script.rb (other_files...) -- script_arguments
93
-
94
- options:
95
- --help or -h
96
- --version or -v
97
- --quiet
98
- --verbose
99
-
100
- --dll <dll1>,<dll2>,...
101
- --lib <lib1>,<lib2>,...
102
- --gem <gem1>,<gem2>,...
103
-
104
- --no-enc
105
- --encoding <enc1>,<enc2>,...
106
-
107
- --enable-gems
108
- --enable-did-you-mean
109
- --chdir-first
110
- --pause-last
111
- --no-pause-last
112
- --pause-text <text>
113
-
114
- --output-dir <dirname>
115
- --system-dir <dirname>
116
- --data-file <filename>
117
- --encryption-key <key>
118
-
119
- --no-exe
120
- --b2ec-path <bat_to_exe_converter_path>
121
- --icon <iconfile>
122
- --windows or --invisible
123
- --console or --visible
124
- --x64
125
- --uac-admin
126
- --fileversion <string> # ex) 1,2,3,4
127
- --productversion <string> # ex) 1,2,3,4
128
- --productname <string>
129
- --originalfilename <string>
130
- --internalname <string>
131
- --description <string>
132
- --company <string>
133
- --trademarks <string>
134
- --copyright <string>
135
- --privatebuild <string>
136
- --specialbuild <string>
137
- --comments <string>
138
-
139
- --use-upx
140
- --upx-path <upx path>
141
- --upx_targets '<glob>' # ex) 'bin/**/*.dll'
142
- --upx-options <options>
143
-
144
- --zipfile <filename>
145
- --7zip-path <7-zip path>
146
-
147
- --innosetup <inno_script>
148
- --iscc-path <iscc path>
149
-
150
- --create-recipe <recipefile>
151
- --recipe <recipefile>
152
- EOF
153
- end
154
-
155
- # --version
156
- def output_version
157
- puts "Neri #{Neri::VERSION}"
158
- end
159
-
160
- # --create-recipe
161
- def create_recipe(file, hash = options, pre = "Neri.options")
162
- hash.each_pair do |key, value|
163
- case value
164
- when Hash
165
- create_recipe(file, value, pre + "[:#{key}]")
166
- when Numeric, TrueClass, FalseClass
167
- file.puts "#{pre}[:#{key}] = #{value}"
168
- when NilClass
169
- file.puts "#{pre}[:#{key}] = nil"
170
- when String
171
- file.puts "#{pre}[:#{key}] = '#{value.gsub("\\", "\\\\").gsub("'", "\\'")}'"
172
- when Array
173
- file.puts "#{pre}[:#{key}] = " + JSON.generate(value)
174
- end
175
- end
176
- end
177
-
178
-
179
- def check_options
180
- nputs_v "Checking Neri options."
181
- while arg = ARGV.shift
182
- case arg
183
- when "--help", "-h"
184
- output_help
185
- exit
186
- when "--version", "-v"
187
- output_version
188
- exit
189
- when "--quiet", "-q"
190
- options[:quiet] = true
191
- when "--verbose", "-v"
192
- options[:verbose] = true
193
- when "--dll"
194
- options[:dlls] += ARGV.shift.split(/\s*,\s*/)
195
- when "--lib"
196
- options[:libs] += ARGV.shift.split(/\s*,\s*/)
197
- when "--gem"
198
- options[:gems] += ARGV.shift.split(/\s*,\s*/)
199
- when "--no-enc"
200
- options[:encoding] = nil
201
- when "--encoding"
202
- options[:encoding] = ARGV.shift
203
- when "--enable-gems"
204
- options[:enable_gems] = true
205
- when "--enable-did-you-mean"
206
- options[:enable_did_you_mean] = true
207
- when "--chdir-first"
208
- options[:chdir_first] = true
209
- when "--pause-last"
210
- options[:pause_last] = true
211
- when "--no-pause-last"
212
- options[:pause_last] = false
213
- when "--pause-text"
214
- options[:pause_text] = ARGV.shift
215
- options[:pause_last] = true
216
- when "--output-dir"
217
- options[:output_dir] = ARGV.shift
218
- when "--system-dir"
219
- options[:system_dir] = ARGV.shift
220
- when "--data-file"
221
- options[:data_file] = ARGV.shift
222
- when "--encryption-key"
223
- options[:encryption_key] = ARGV.shift
224
- when "--no-exe"
225
- options[:no_exe] = true
226
- when "--b2ec-path"
227
- options[:b2ec_path] = ARGV.shift
228
- when "--icon"
229
- options[:b2ec][:icon] = ARGV.shift
230
- when "--windows", "--invisible"
231
- options[:b2ec][:invisible] = true
232
- when "--console", "--visible"
233
- options[:b2ec][:invisible] = false
234
- when "--x64"
235
- options[:b2ec][:x64] = true
236
- when "--uac-admin"
237
- options[:b2ec][:uac_admin] = true
238
- when "--fileversion"
239
- options[:b2ec][:fileversion] = ARGV.shift
240
- when "--productversion"
241
- options[:b2ec][:productversion] = ARGV.shift
242
- when "--productname"
243
- options[:b2ec][:productname] = ARGV.shift
244
- when "--originalfilename"
245
- options[:b2ec][:originalfilename] = ARGV.shift
246
- when "--internalname"
247
- options[:b2ec][:internalname] = ARGV.shift
248
- when "--description"
249
- options[:b2ec][:description] = ARGV.shift
250
- when "--company"
251
- options[:b2ec][:company] = ARGV.shift
252
- when "--trademarks"
253
- options[:b2ec][:trademarks] = ARGV.shift
254
- when "--copyright"
255
- options[:b2ec][:copyright] = ARGV.shift
256
- when "--privatebuild"
257
- options[:b2ec][:privatebuild] = ARGV.shift
258
- when "--specialbuild"
259
- options[:b2ec][:specialbuild] = ARGV.shift
260
- when "--comments"
261
- options[:b2ec][:comments] = ARGV.shift
262
- when "--use-upx"
263
- options[:use_upx] = true
264
- when "--upx-path"
265
- options[:upx_path] = ARGV.shift
266
- when "--upx-targets"
267
- options[:upx_targets] += ARGV.shift.split(/\s*,\s*/)
268
- when "--upx-options"
269
- options[:upx_options] = ARGV.shift
270
- when "--zipfile"
271
- options[:zipfile] = ARGV.shift
272
- when "--7zip-path"
273
- options[:sevenzip_path] = ARGV.shift
274
- when "--innosetup"
275
- options[:inno_script] = ARGV.shift
276
- when "--iscc-path"
277
- options[:iscc_path] = ARGV.shift
278
- when "--create-recipe"
279
- require "json"
280
- filename = ARGV.shift
281
- nputs "Creating recipe_file '#{filename}'."
282
- open(filename, "w:utf-8"){|file| create_recipe(file)}
283
- exit
284
- when "--recipe"
285
- filename = ARGV.shift
286
- nputs_v "Loading recipe_file '#{filename}'."
287
- load filename
288
- when "--"
289
- break
290
- when /^(--.+)/
291
- puts "** Invalid Option '#{arg}'! **"
292
- output_help
293
- exit
294
- else
295
- @data_files.push(arg)
296
- end
297
- end
298
-
299
- if @data_files.empty?
300
- puts "** No Script File! **"
301
- output_help
302
- exit
303
- end
304
-
305
- if @data_files.size > 1 || options[:encryption_key]
306
- options[:data_file] ||= File.basename(@data_files.first, ".*") + ".dat"
307
- end
308
- end
309
-
310
-
311
- # check dependencies
312
- def rb_dependencies()
313
- return $LOADED_FEATURES.uniq
314
- end
315
-
316
- def dll_dependencies()
317
- require "Win32API"
318
-
319
- enumprocessmodules = Win32API.new("psapi" , "EnumProcessModules", ["L","P","L","P"], "L")
320
- getmodulefilename = Win32API.new("kernel32", "GetModuleFileNameW", ["L","P","L"], "L")
321
- getcurrentprocess = Win32API.new("kernel32", "GetCurrentProcess" , [], "L")
322
-
323
- bytes_needed = 4 * 32
324
- module_handle_buffer = nil
325
- process_handle = getcurrentprocess.call()
326
- loop do
327
- module_handle_buffer = "\x00" * bytes_needed
328
- bytes_needed_buffer = [0].pack("I")
329
- r = enumprocessmodules.call(process_handle, module_handle_buffer, module_handle_buffer.size, bytes_needed_buffer)
330
- bytes_needed = bytes_needed_buffer.unpack("I")[0]
331
- break if bytes_needed <= module_handle_buffer.size
332
- end
333
-
334
- handles = module_handle_buffer.unpack("I*")
335
- dependencies = handles.select { |handle| handle > 0 }.map do |handle|
336
- str = "\x00\x00" * 256
337
- modulefilename_length = getmodulefilename.call(handle, str, str.size)
338
- modulefilename = str[0, modulefilename_length * 2].force_encoding("UTF-16LE").encode("UTF-8")
339
- end
340
-
341
- dependencies.map!{|dep| dep.sub(/^\\\\\?\\/, "")}
342
- if File::ALT_SEPARATOR
343
- dependencies.map!{|dep| dep.tr(File::ALT_SEPARATOR, File::SEPARATOR)}
344
- end
345
- dependencies.delete(rubyexe)
346
-
347
- return dependencies.uniq
348
- end
349
-
350
- def ruby_dependencies()
351
- dependencies = Dir.glob(File.join(bindir, "**", "*.manifest"))
352
- dependencies.push(rubyexe)
353
- return dependencies.uniq
354
- end
355
-
356
- def additional_dlls_dependencies()
357
- dependencies = []
358
- options[:dlls].each do |dll|
359
- dependencies += Dir.glob(File.join(bindir, "**", dll))
360
- dependencies += Dir.glob(File.join(bindir, "**", dll + ".*"))
361
- end
362
- return dependencies.uniq
363
- end
364
-
365
- def additional_libs_dependencies()
366
- dependencies = []
367
- options[:libs].each do |lib|
368
- $LOAD_PATH.each do |path|
369
- dependencies += Dir.glob(File.join(path, lib))
370
- dependencies += Dir.glob(File.join(path, lib + ".*"))
371
- dependencies += Dir.glob(File.join(path, lib, "**", "*"))
372
- end
373
- end
374
- return dependencies.uniq
375
- end
376
-
377
- def additional_gems_dependencies()
378
- require "rubygems"
379
- dependencies = []
380
- rubygems_dir = File.join(Gem.dir, "gems")
381
- options[:gems].each do |gem|
382
- gem.sub!(/\:(.+)/, "")
383
- targets = $1.to_s.split("|")
384
- targets.push("lib/**/*")
385
- gem += "-*" unless gem.match("-")
386
- gemdir = Dir.glob(File.join(rubygems_dir, gem)).sort.last
387
- next unless gemdir
388
- targets.each do |target|
389
- dependencies += Dir.glob(File.join(gemdir, target))
390
- end
391
- end
392
- return dependencies.uniq
393
- end
394
-
395
- def encoding_dependencies()
396
- return [] unless options[:encoding]
397
- dependencies = []
398
- enc_dir = Dir.glob(File.join(RbConfig::CONFIG["archdir"] || RbConfig::TOPDIR, "**", "enc")).first
399
-
400
- options[:encoding].split(/\s*,\s*/).each do |enc|
401
- case enc
402
- when "ja"
403
- %w[windows_31j.so japanese_sjis.so encdb.so].each do |enc_name|
404
- dependencies += Dir.glob(File.join(enc_dir, "**", enc_name))
405
- end
406
- else
407
- dependencies += Dir.glob(File.join(enc_dir, "**", enc))
408
- dependencies += Dir.glob(File.join(enc_dir, "**", enc + ".*"))
409
- end
410
- end
411
-
412
- return dependencies.uniq
413
- end
414
-
415
- def check_dependencies()
416
- nputs "Running script '#{@data_files.first}' to check dependencies."
417
- begin
418
- load @data_files.first
419
- rescue SystemExit
420
- end
421
- nputs "Script '#{@data_files.first}' end."
422
-
423
- if defined? DXRuby
424
- require "neri/dxruby"
425
- @use_dxruby = true
426
- options[:b2ec][:invisible] = true if options[:b2ec][:invisible] == nil
427
- end
428
- if defined? DXRuby::Tiled
429
- require "neri/dxruby_tiled"
430
- @use_dxruby_tiled = true
431
- end
432
- if defined? Ayame
433
- require "neri/ayame"
434
- @use_ayame = true
435
- end
436
-
437
- if options[:b2ec][:invisible] == nil
438
- options[:b2ec][:invisible] = true if File.extname(@data_files.first) == ".rbw"
439
- end
440
- if options[:pause_last] == nil
441
- options[:pause_last] = true unless options[:b2ec][:invisible]
442
- end
443
-
444
- require "rbconfig"
445
- dependencies = []
446
- dependencies += rb_dependencies
447
- dependencies += dll_dependencies
448
- dependencies += ruby_dependencies
449
- dependencies += additional_dlls_dependencies
450
- dependencies += additional_libs_dependencies
451
- dependencies += additional_gems_dependencies
452
- dependencies += encoding_dependencies
453
- dependencies = select_dependencies(dependencies)
454
-
455
- size = dependencies.map{|d| File.size(d)}.inject(&:+)
456
- nputs "#{dependencies.size} files, #{size} bytes dependencies."
457
- if options[:verbose]
458
- dependencies.each do |dependency|
459
- nputs_v " - #{dependency}"
460
- end
461
- end
462
-
463
- return dependencies
464
- end
465
-
466
- def select_dependencies(dependencies)
467
- dependencies.select! do |dependency|
468
- dependency.start_with?(rubydir + File::SEPARATOR)
469
- end
470
-
471
- @data_files.each do |file|
472
- dependencies.delete(File.expand_path(file))
473
- end
474
-
475
- unless options[:enable_gems]
476
- dependencies.delete_if do |dependency|
477
- File.basename(dependency) == "rubygems.rb" ||
478
- dependency.split(File::SEPARATOR).index("rubygems")
479
- end
480
- end
481
- unless options[:enable_did_you_mean]
482
- dependencies.delete_if do |dependency|
483
- File.basename(dependency) == "did_you_mean.rb" ||
484
- dependency.split(File::SEPARATOR).index("did_you_mean")
485
- end
486
- end
487
-
488
- return dependencies.uniq
489
- end
490
-
491
-
492
- def copy_files(dependencies)
493
- nputs "Copying dependencies."
494
- require "fileutils"
495
- options[:output_dir] ||= File.basename(@data_files.first, ".*")
496
- src_dir = File.join(rubydir, "")
497
- desc_dir = File.join(options[:output_dir], options[:system_dir], "")
498
-
499
- @system_files = dependencies.map do |file|
500
- [file, file.sub(src_dir, desc_dir)]
501
- end
502
- unless options[:enable_gems]
503
- @system_files.each do |src, desc|
504
- desc.sub!(/\/gems(\/\d+\.\d+\.\d+\/)gems\/(.+?)\-[^\/]+\/lib\//, "/vendor_ruby\\1")
505
- end
506
- end
507
-
508
- @system_files.each do |src, desc|
509
- FileUtils.makedirs(File.dirname(desc))
510
- if File.file?(src)
511
- FileUtils.copy(src, desc)
512
- nputs_v " #{src}\n -> #{desc}"
513
- end
514
- end
515
- FileUtils.copy(@data_files.first, desc_dir) unless options[:data_file]
516
- end
517
-
518
-
519
- def create_batch()
520
- nputs "Creating batch_file '#{batchfile}'."
521
-
522
- enc = system(%(ruby --disable-gems -e "'#{@data_files.first}'" >NUL 2>&1)) ?
523
- '' : ' -e "# coding: utf-8"'
524
-
525
- unless options[:enable_gems]
526
- @rubyopt += " --disable-gems" unless @rubyopt.match("--disable-gems")
527
- end
528
-
529
- ruby_code = ""
530
- if options[:encryption_key]
531
- require "digest/sha2"
532
- @encryption_key = Digest::SHA2.hexdigest(options[:encryption_key])
533
- ruby_code = "Neri.key='#{@encryption_key}';"
534
- end
535
- if options[:data_file]
536
- data_file = "%~dp0#{options[:system_dir]}#{File::ALT_SEPARATOR || File::SEPARATOR}#{options[:data_file]}"
537
- ruby_code += "Neri.datafile='#{data_file}';"
538
- ruby_code += "load '#{File.basename(@data_files.first)}'"
539
- else
540
- ruby_code += "load '%~dp0#{options[:system_dir]}#{File::ALT_SEPARATOR}#{File.basename(@data_files.first)}'"
541
- end
542
-
543
- pause_code = ""
544
- if options[:pause_last]
545
- if options[:pause_text]
546
- pause_code = "echo.\necho #{options[:pause_text]}\npause > nul"
547
- else
548
- pause_code = "echo.\npause"
549
- end
550
- end
551
-
552
- r = " -rneri"
553
- r += " -rneri/dxruby" if @use_dxruby
554
- r += " -rneri/dxruby_tiled" if @use_dxruby_tiled
555
- r += " -rneri/ayame" if @use_ayame
556
-
557
- open(batchfile, "w:#{Encoding.default_external.name}") do |f|
558
- f.puts <<-EOF
559
- @echo off
560
- setlocal
561
- set PATH=%~dp0#{options[:system_dir]}\\#{relative_path(bindir)};%PATH%
562
- #{options[:chdir_first] ? 'cd /d "%~dp0"' : ''}
563
- if %~x0 == .exe ( shift )
564
- #{relative_path(rubyexe, bindir)}#{r} #{@rubyopt}#{enc} -e "#{ruby_code}"
565
- #{pause_code}
566
- endlocal
567
- EOF
568
- end
569
- end
570
-
571
-
572
- def create_datafile()
573
- nputs "Creating data_file '#{datafile}'."
574
- data_files = @data_files.select { |file| File.file? file }
575
- @data_files.select { |file| File.directory? file }.each do |dir|
576
- data_files += Dir.glob(dir + "/**/*").select { |file| File.file? file }
577
- end
578
- Neri.key = @encryption_key || "0" * 64
579
- open(datafile, "wb") do |f|
580
- pos = 0
581
- files_str = data_files.map{|file|
582
- filename = File.expand_path(file)
583
- filename = relative_path(filename, rubydir, "*neri*" + File::SEPARATOR)
584
- filename = relative_path(filename, Dir.pwd)
585
- filedata = [filename, File.size(file), pos]
586
- pos += File.size(file)
587
- pos += BLOCK_LENGTH - pos % BLOCK_LENGTH unless pos % BLOCK_LENGTH == 0
588
- nputs_v " - #{filename}:#{File.size(file)} bytes"
589
- filedata.join("\t")
590
- }.join("\n").encode(Encoding::UTF_8)
591
-
592
- f.write(sprintf("%#{BLOCK_LENGTH}d", files_str.bytesize))
593
- f.write(xor(files_str))
594
- data_files.each do |file|
595
- f.write(xor(File.binread(file)))
596
- end
597
- end
598
- end
599
-
600
-
601
- def bat_to_exe_converter()
602
- exefile = batchfile.sub(/\.bat$/, ".exe")
603
- nputs "Creating exe_file '#{exefile}'."
604
- File.delete(exefile) if File.exist?(exefile)
605
- args = %[ /bat "#{batchfile}" /exe "#{exefile}"]
606
- if options[:b2ec][:x64] == nil
607
- options[:b2ec][:x64] = true if RbConfig::CONFIG["target"].to_s.index("64")
608
- end
609
-
610
- args += options[:b2ec].map{|key, value|
611
- case value
612
- when String; %[ /#{key.to_s.tr('_', '-')} "#{value}"]
613
- when true; %[ /#{key.to_s.tr('_', '-')}]
614
- else; %[]
615
- end
616
- }.join("")
617
- begin
618
- exec = %(#{options[:b2ec_path]}#{args})
619
- nputs_v exec
620
- options[:quiet] ? `#{exec}` : system(exec)
621
- rescue SystemCallError
622
- end
623
- if File.exist?(exefile)
624
- File.delete(batchfile)
625
- else
626
- nputs "Failed to create exe_file."
627
- end
628
- end
629
-
630
-
631
- def upx()
632
- nputs "Compressing with UPX."
633
- options[:upx_targets].each do |target|
634
- Dir.glob(File.join(options[:output_dir], options[:system_dir], target)).each do |target_path|
635
- exec = %(#{options[:upx_path]} #{options[:upx_options]} "#{target_path}")
636
- nputs_v exec
637
- options[:quiet] ? `#{exec}` : system(exec)
638
- end
639
- end
640
- end
641
-
642
-
643
- def create_zipfile()
644
- nputs "Creating zip_file '#{options[:zipfile]}'."
645
- File.delete(options[:zipfile]) if File.exist?(options[:zipfile])
646
- exec = %(#{options[:sevenzip_path]} a #{options[:zipfile]} "#{options[:output_dir]}")
647
- nputs_v exec
648
- options[:quiet] ? `#{exec}` : system(exec)
649
- end
650
-
651
-
652
- def inno_setup()
653
- filename = options[:inno_script]
654
- script = "[Setup]\n"
655
- if File.exist?(filename)
656
- script = File.read(filename, encoding: Encoding::UTF_8)
657
- filename = File.basename(filename, ".*") + "_tmp" + File.extname(filename)
658
- end
659
-
660
- version = options[:b2ec][:productversion] || options[:b2ec][:fileversion]
661
- if !script.match(/^AppName=/) && options[:b2ec][:productname]
662
- script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppName=#{options[:b2ec][:productname]}#{$2}" }
663
- end
664
- if !script.match(/^AppVersion=/) && version
665
- script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppVersion=#{version}#{$2}" }
666
- end
667
- if !script.match(/^AppVerName=/) && options[:b2ec][:productname] && version
668
- script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppVerName=#{options[:b2ec][:productname]} #{version}#{$2}" }
669
- end
670
- if !script.match(/^AppPublisher=/) && options[:b2ec][:company]
671
- script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppPublisher=#{options[:b2ec][:company]}#{$2}" }
672
- end
673
- if !script.match(/^AppCopyright=/) && options[:b2ec][:copyright]
674
- script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppCopyright=#{options[:b2ec][:copyright]}#{$2}" }
675
- end
676
-
677
- script += "\n[Files]\n" unless script.match(/^\[Files\]/)
678
- dir = File.expand_path(options[:output_dir])
679
- files_str = ""
680
- Dir.glob(File.join(dir, "**", "*")).each do |file|
681
- next unless File.file? file
682
- dist_dir = to_winpath(File::SEPARATOR + File.dirname(relative_path(file, dir)))
683
- dist_dir = "" if dist_dir == "\\."
684
- files_str += "\nSource: \"#{to_winpath(file)}\"; DistDir: \"{app}#{dist_dir}\""
685
- files_str += "; Flags: isreadme" if File.basename(file).match(/^readme/i)
686
- end
687
- script.sub!(/^(\[Files\])(\s*)/i){ "#{$1}#{files_str}#{$2}" }
688
-
689
- File.write(filename, script)
690
- exec = %(#{options[:iscc_path]} "#{filename}")
691
- nputs_v exec
692
- options[:quiet] ? `#{exec}` : system(exec)
693
- end
694
-
695
- def run()
696
- check_options
697
- dependencies = check_dependencies
698
- copy_files(dependencies)
699
- create_batch
700
- create_datafile if options[:data_file]
701
- bat_to_exe_converter unless options[:no_exe]
702
- upx if options[:use_upx]
703
- create_zipfile if options[:zipfile]
704
- inno_setup if options[:inno_script]
705
- nputs "Neri Finished."
706
- end
707
-
708
- private
709
-
710
- def nputs(str)
711
- puts "=== #{str}" unless options[:quiet]
712
- end
713
-
714
- def nputs_v(str)
715
- puts str if options[:verbose]
716
- end
717
- end
718
- end
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require "neri"
5
+
6
+ module Neri
7
+ @data_files = []
8
+ @system_files = []
9
+
10
+ @options = {
11
+ quiet: false,
12
+ verbose: false,
13
+
14
+ dlls: [],
15
+ libs: [],
16
+ gems: [],
17
+ encoding: "*",
18
+
19
+ enable_gems: false,
20
+ enable_did_you_mean: false,
21
+ chdir_first: false,
22
+ pause_last: nil,
23
+ pause_text: nil,
24
+
25
+ output_dir: nil,
26
+ system_dir: "system",
27
+
28
+ data_file: nil,
29
+ encryption_key: nil,
30
+
31
+ no_exe: false,
32
+ b2ec_path: "Bat_To_Exe_Converter.exe",
33
+ b2ec: {
34
+ icon: "#{File.expand_path(File.dirname(__FILE__) + '/../../share/default.ico')}",
35
+ invisible: nil,
36
+ x64: nil,
37
+ uac_admin: nil,
38
+ fileversion: nil,
39
+ productversion: nil,
40
+ productname: nil,
41
+ originalfilename: nil,
42
+ internalname: nil,
43
+ description: nil,
44
+ company: nil,
45
+ trademarks: nil,
46
+ copyright: nil,
47
+ privatebuild: nil,
48
+ specialbuild: nil,
49
+ comments: nil
50
+ },
51
+
52
+ use_upx: false,
53
+ upx_path: "upx.exe",
54
+ upx_targets: ["bin/**/*.dll"],
55
+ upx_options: "",
56
+
57
+ zipfile: nil,
58
+ sevenzip_path: "7z.exe",
59
+
60
+ inno_script: nil,
61
+ iscc_path: "iscc",
62
+ }
63
+ @rubyopt = ENV["RUBYOPT"].to_s
64
+ @encryption_key = nil
65
+
66
+ @use_dxruby = false
67
+ @use_dxruby_tiled = false
68
+ @use_ayame = false
69
+
70
+ class << self
71
+
72
+ attr_reader :options
73
+
74
+ def relative_path(path, basedir=rubydir, prepath = "")
75
+ basedir.concat(File::SEPARATOR) unless basedir.end_with?(File::SEPARATOR)
76
+ return path.start_with?(basedir) ? path.sub(basedir, prepath) : path
77
+ end
78
+
79
+ def to_winpath(path)
80
+ return File::ALT_SEPARATOR ? path.tr(File::SEPARATOR, File::ALT_SEPARATOR) : path
81
+ end
82
+
83
+ def bindir( ); RbConfig::CONFIG["bindir"] || File.join(rubydir, "bin"); end
84
+ def rubydir( ); RbConfig::TOPDIR; end
85
+ def rubyexe( ); RbConfig.ruby; end
86
+ def batchfile(); File.join(options[:output_dir], "#{File.basename(@data_files.first, ".*")}.bat"); end
87
+ def datafile( ); File.join(options[:output_dir], options[:system_dir], options[:data_file]); end
88
+
89
+ # --help
90
+ def output_help
91
+ puts <<-EOF
92
+ usage: neri [options] script.rb (other_files...) -- script_arguments
93
+
94
+ options:
95
+ --help or -h
96
+ --version or -v
97
+ --quiet
98
+ --verbose
99
+
100
+ --dll <dll1>,<dll2>,...
101
+ --lib <lib1>,<lib2>,...
102
+ --gem <gem1>,<gem2>,...
103
+
104
+ --no-enc
105
+ --encoding <enc1>,<enc2>,...
106
+
107
+ --enable-gems
108
+ --enable-did-you-mean
109
+ --chdir-first
110
+ --pause-last
111
+ --no-pause-last
112
+ --pause-text <text>
113
+
114
+ --output-dir <dirname>
115
+ --system-dir <dirname>
116
+ --data-file <filename>
117
+ --encryption-key <key>
118
+
119
+ --no-exe
120
+ --b2ec-path <bat_to_exe_converter_path>
121
+ --icon <iconfile>
122
+ --windows or --invisible
123
+ --console or --visible
124
+ --x64
125
+ --uac-admin
126
+ --fileversion <string> # ex) 1,2,3,4
127
+ --productversion <string> # ex) 1,2,3,4
128
+ --productname <string>
129
+ --originalfilename <string>
130
+ --internalname <string>
131
+ --description <string>
132
+ --company <string>
133
+ --trademarks <string>
134
+ --copyright <string>
135
+ --privatebuild <string>
136
+ --specialbuild <string>
137
+ --comments <string>
138
+
139
+ --use-upx
140
+ --upx-path <upx path>
141
+ --upx_targets '<glob>' # ex) 'bin/**/*.dll'
142
+ --upx-options <options>
143
+
144
+ --zipfile <filename>
145
+ --7zip-path <7-zip path>
146
+
147
+ --innosetup <inno_script>
148
+ --iscc-path <iscc path>
149
+
150
+ --create-recipe <recipefile>
151
+ --recipe <recipefile>
152
+ EOF
153
+ end
154
+
155
+ # --version
156
+ def output_version
157
+ puts "Neri #{Neri::VERSION}"
158
+ end
159
+
160
+ # --create-recipe
161
+ def create_recipe(file, hash = options, pre = "Neri.options")
162
+ hash.each_pair do |key, value|
163
+ case value
164
+ when Hash
165
+ create_recipe(file, value, pre + "[:#{key}]")
166
+ when Numeric, TrueClass, FalseClass
167
+ file.puts "#{pre}[:#{key}] = #{value}"
168
+ when NilClass
169
+ file.puts "#{pre}[:#{key}] = nil"
170
+ when String
171
+ file.puts "#{pre}[:#{key}] = '#{value.gsub("\\", "\\\\").gsub("'", "\\'")}'"
172
+ when Array
173
+ file.puts "#{pre}[:#{key}] = " + JSON.generate(value)
174
+ end
175
+ end
176
+ end
177
+
178
+
179
+ def check_options
180
+ nputs_v "Checking Neri options."
181
+ while arg = ARGV.shift
182
+ case arg
183
+ when "--help", "-h"
184
+ output_help
185
+ exit
186
+ when "--version", "-v"
187
+ output_version
188
+ exit
189
+ when "--quiet", "-q"
190
+ options[:quiet] = true
191
+ when "--verbose", "-v"
192
+ options[:verbose] = true
193
+ when "--dll"
194
+ options[:dlls] += ARGV.shift.split(/\s*,\s*/)
195
+ when "--lib"
196
+ options[:libs] += ARGV.shift.split(/\s*,\s*/)
197
+ when "--gem"
198
+ options[:gems] += ARGV.shift.split(/\s*,\s*/)
199
+ when "--no-enc"
200
+ options[:encoding] = nil
201
+ when "--encoding"
202
+ options[:encoding] = ARGV.shift
203
+ when "--enable-gems"
204
+ options[:enable_gems] = true
205
+ when "--enable-did-you-mean"
206
+ options[:enable_did_you_mean] = true
207
+ when "--chdir-first"
208
+ options[:chdir_first] = true
209
+ when "--pause-last"
210
+ options[:pause_last] = true
211
+ when "--no-pause-last"
212
+ options[:pause_last] = false
213
+ when "--pause-text"
214
+ options[:pause_text] = ARGV.shift
215
+ options[:pause_last] = true
216
+ when "--output-dir"
217
+ options[:output_dir] = ARGV.shift
218
+ when "--system-dir"
219
+ options[:system_dir] = ARGV.shift
220
+ when "--data-file"
221
+ options[:data_file] = ARGV.shift
222
+ when "--encryption-key"
223
+ options[:encryption_key] = ARGV.shift
224
+ when "--no-exe"
225
+ options[:no_exe] = true
226
+ when "--b2ec-path"
227
+ options[:b2ec_path] = ARGV.shift
228
+ when "--icon"
229
+ options[:b2ec][:icon] = ARGV.shift
230
+ when "--windows", "--invisible"
231
+ options[:b2ec][:invisible] = true
232
+ when "--console", "--visible"
233
+ options[:b2ec][:invisible] = false
234
+ when "--x64"
235
+ options[:b2ec][:x64] = true
236
+ when "--uac-admin"
237
+ options[:b2ec][:uac_admin] = true
238
+ when "--fileversion"
239
+ options[:b2ec][:fileversion] = ARGV.shift
240
+ when "--productversion"
241
+ options[:b2ec][:productversion] = ARGV.shift
242
+ when "--productname"
243
+ options[:b2ec][:productname] = ARGV.shift
244
+ when "--originalfilename"
245
+ options[:b2ec][:originalfilename] = ARGV.shift
246
+ when "--internalname"
247
+ options[:b2ec][:internalname] = ARGV.shift
248
+ when "--description"
249
+ options[:b2ec][:description] = ARGV.shift
250
+ when "--company"
251
+ options[:b2ec][:company] = ARGV.shift
252
+ when "--trademarks"
253
+ options[:b2ec][:trademarks] = ARGV.shift
254
+ when "--copyright"
255
+ options[:b2ec][:copyright] = ARGV.shift
256
+ when "--privatebuild"
257
+ options[:b2ec][:privatebuild] = ARGV.shift
258
+ when "--specialbuild"
259
+ options[:b2ec][:specialbuild] = ARGV.shift
260
+ when "--comments"
261
+ options[:b2ec][:comments] = ARGV.shift
262
+ when "--use-upx"
263
+ options[:use_upx] = true
264
+ when "--upx-path"
265
+ options[:upx_path] = ARGV.shift
266
+ when "--upx-targets"
267
+ options[:upx_targets] += ARGV.shift.split(/\s*,\s*/)
268
+ when "--upx-options"
269
+ options[:upx_options] = ARGV.shift
270
+ when "--zipfile"
271
+ options[:zipfile] = ARGV.shift
272
+ when "--7zip-path"
273
+ options[:sevenzip_path] = ARGV.shift
274
+ when "--innosetup"
275
+ options[:inno_script] = ARGV.shift
276
+ when "--iscc-path"
277
+ options[:iscc_path] = ARGV.shift
278
+ when "--create-recipe"
279
+ require "json"
280
+ filename = ARGV.shift
281
+ nputs "Creating recipe_file '#{filename}'."
282
+ open(filename, "w:utf-8"){|file| create_recipe(file)}
283
+ exit
284
+ when "--recipe"
285
+ filename = ARGV.shift
286
+ nputs_v "Loading recipe_file '#{filename}'."
287
+ load filename
288
+ when "--"
289
+ break
290
+ when /^(--.+)/
291
+ puts "** Invalid Option '#{arg}'! **"
292
+ output_help
293
+ exit
294
+ else
295
+ @data_files.push(arg)
296
+ end
297
+ end
298
+
299
+ if @data_files.empty?
300
+ puts "** No Script File! **"
301
+ output_help
302
+ exit
303
+ end
304
+
305
+ if @data_files.size > 1 || options[:encryption_key]
306
+ options[:data_file] ||= File.basename(@data_files.first, ".*") + ".dat"
307
+ end
308
+ end
309
+
310
+
311
+ # check dependencies
312
+ def rb_dependencies()
313
+ return $LOADED_FEATURES.uniq
314
+ end
315
+
316
+ def dll_dependencies()
317
+ require "Win32API"
318
+
319
+ enumprocessmodules = Win32API.new("psapi" , "EnumProcessModules", ["L","P","L","P"], "L")
320
+ getmodulefilename = Win32API.new("kernel32", "GetModuleFileNameW", ["L","P","L"], "L")
321
+ getcurrentprocess = Win32API.new("kernel32", "GetCurrentProcess" , [], "L")
322
+
323
+ bytes_needed = 4 * 32
324
+ module_handle_buffer = nil
325
+ process_handle = getcurrentprocess.call()
326
+ loop do
327
+ module_handle_buffer = "\x00" * bytes_needed
328
+ bytes_needed_buffer = [0].pack("I")
329
+ r = enumprocessmodules.call(process_handle, module_handle_buffer, module_handle_buffer.size, bytes_needed_buffer)
330
+ bytes_needed = bytes_needed_buffer.unpack("I")[0]
331
+ break if bytes_needed <= module_handle_buffer.size
332
+ end
333
+
334
+ handles = module_handle_buffer.unpack("I*")
335
+ dependencies = handles.select { |handle| handle > 0 }.map do |handle|
336
+ str = "\x00\x00" * 256
337
+ modulefilename_length = getmodulefilename.call(handle, str, str.size)
338
+ modulefilename = str[0, modulefilename_length * 2].force_encoding("UTF-16LE").encode("UTF-8")
339
+ end
340
+
341
+ dependencies.map!{|dep| dep.sub(/^\\\\\?\\/, "")}
342
+ if File::ALT_SEPARATOR
343
+ dependencies.map!{|dep| dep.tr(File::ALT_SEPARATOR, File::SEPARATOR)}
344
+ end
345
+ dependencies.delete(rubyexe)
346
+
347
+ return dependencies.uniq
348
+ end
349
+
350
+ def ruby_dependencies()
351
+ dependencies = Dir.glob(File.join(bindir, "**", "*.manifest"))
352
+ dependencies.push(rubyexe)
353
+ return dependencies.uniq
354
+ end
355
+
356
+ def additional_dlls_dependencies()
357
+ dependencies = []
358
+ options[:dlls].each do |dll|
359
+ dependencies += Dir.glob(File.join(bindir, "**", dll))
360
+ dependencies += Dir.glob(File.join(bindir, "**", dll + ".*"))
361
+ end
362
+ return dependencies.uniq
363
+ end
364
+
365
+ def additional_libs_dependencies()
366
+ dependencies = []
367
+ options[:libs].each do |lib|
368
+ $LOAD_PATH.each do |path|
369
+ dependencies += Dir.glob(File.join(path, lib))
370
+ dependencies += Dir.glob(File.join(path, lib + ".*"))
371
+ dependencies += Dir.glob(File.join(path, lib, "**", "*"))
372
+ end
373
+ end
374
+ return dependencies.uniq
375
+ end
376
+
377
+ def additional_gems_dependencies()
378
+ require "rubygems"
379
+ dependencies = []
380
+ rubygems_dir = File.join(Gem.dir, "gems")
381
+ options[:gems].each do |gem|
382
+ gem.sub!(/\:(.+)/, "")
383
+ targets = $1.to_s.split("|")
384
+ targets.push("lib/**/*")
385
+ gem += "-*" unless gem.match("-")
386
+ gemdir = Dir.glob(File.join(rubygems_dir, gem)).sort.last
387
+ next unless gemdir
388
+ targets.each do |target|
389
+ dependencies += Dir.glob(File.join(gemdir, target))
390
+ end
391
+ end
392
+ return dependencies.uniq
393
+ end
394
+
395
+ def encoding_dependencies()
396
+ return [] unless options[:encoding]
397
+ dependencies = []
398
+ enc_dir = Dir.glob(File.join(RbConfig::CONFIG["archdir"] || RbConfig::TOPDIR, "**", "enc")).first
399
+
400
+ options[:encoding].split(/\s*,\s*/).each do |enc|
401
+ case enc
402
+ when "ja"
403
+ %w[windows_31j.so japanese_sjis.so encdb.so].each do |enc_name|
404
+ dependencies += Dir.glob(File.join(enc_dir, "**", enc_name))
405
+ end
406
+ else
407
+ dependencies += Dir.glob(File.join(enc_dir, "**", enc))
408
+ dependencies += Dir.glob(File.join(enc_dir, "**", enc + ".*"))
409
+ end
410
+ end
411
+
412
+ return dependencies.uniq
413
+ end
414
+
415
+ def check_dependencies()
416
+ nputs "Running script '#{@data_files.first}' to check dependencies."
417
+ begin
418
+ load @data_files.first
419
+ rescue SystemExit
420
+ end
421
+ nputs "Script '#{@data_files.first}' end."
422
+
423
+ if defined? DXRuby
424
+ require "neri/dxruby"
425
+ @use_dxruby = true
426
+ options[:b2ec][:invisible] = true if options[:b2ec][:invisible] == nil
427
+ end
428
+ if defined? DXRuby::Tiled
429
+ require "neri/dxruby_tiled"
430
+ @use_dxruby_tiled = true
431
+ end
432
+ if defined? Ayame
433
+ require "neri/ayame"
434
+ @use_ayame = true
435
+ end
436
+
437
+ if options[:b2ec][:invisible] == nil
438
+ options[:b2ec][:invisible] = true if File.extname(@data_files.first) == ".rbw"
439
+ end
440
+ if options[:pause_last] == nil
441
+ options[:pause_last] = true unless options[:b2ec][:invisible]
442
+ end
443
+
444
+ require "rbconfig"
445
+ dependencies = []
446
+ dependencies += rb_dependencies
447
+ dependencies += dll_dependencies
448
+ dependencies += ruby_dependencies
449
+ dependencies += additional_dlls_dependencies
450
+ dependencies += additional_libs_dependencies
451
+ dependencies += additional_gems_dependencies
452
+ dependencies += encoding_dependencies
453
+ dependencies = select_dependencies(dependencies)
454
+
455
+ size = dependencies.map{|d| File.size(d)}.inject(&:+)
456
+ nputs "#{dependencies.size} files, #{size} bytes dependencies."
457
+ if options[:verbose]
458
+ dependencies.each do |dependency|
459
+ nputs_v " - #{dependency}"
460
+ end
461
+ end
462
+
463
+ return dependencies
464
+ end
465
+
466
+ def select_dependencies(dependencies)
467
+ dependencies.select! do |dependency|
468
+ dependency.start_with?(rubydir + File::SEPARATOR)
469
+ end
470
+
471
+ @data_files.each do |file|
472
+ dependencies.delete(File.expand_path(file))
473
+ end
474
+
475
+ unless options[:enable_gems]
476
+ dependencies.delete_if do |dependency|
477
+ File.basename(dependency) == "rubygems.rb" ||
478
+ dependency.split(File::SEPARATOR).index("rubygems")
479
+ end
480
+ end
481
+ unless options[:enable_did_you_mean]
482
+ dependencies.delete_if do |dependency|
483
+ File.basename(dependency) == "did_you_mean.rb" ||
484
+ dependency.split(File::SEPARATOR).index("did_you_mean")
485
+ end
486
+ end
487
+
488
+ return dependencies.uniq
489
+ end
490
+
491
+
492
+ def copy_files(dependencies)
493
+ nputs "Copying dependencies."
494
+ require "fileutils"
495
+ options[:output_dir] ||= File.basename(@data_files.first, ".*")
496
+ src_dir = File.join(rubydir, "")
497
+ desc_dir = File.join(options[:output_dir], options[:system_dir], "")
498
+
499
+ @system_files = dependencies.map do |file|
500
+ [file, file.sub(src_dir, desc_dir)]
501
+ end
502
+ unless options[:enable_gems]
503
+ @system_files.each do |src, desc|
504
+ desc.sub!(/\/gems(\/\d+\.\d+\.\d+\/)gems\/(.+?)\-[^\/]+\/lib\//, "/vendor_ruby\\1")
505
+ end
506
+ end
507
+
508
+ @system_files.each do |src, desc|
509
+ FileUtils.makedirs(File.dirname(desc))
510
+ if File.file?(src)
511
+ FileUtils.copy(src, desc)
512
+ nputs_v " #{src}\n -> #{desc}"
513
+ end
514
+ end
515
+ FileUtils.copy(@data_files.first, desc_dir) unless options[:data_file]
516
+ end
517
+
518
+
519
+ def create_batch()
520
+ nputs "Creating batch_file '#{batchfile}'."
521
+
522
+ enc = system(%(ruby --disable-gems -e "'#{@data_files.first}'" >NUL 2>&1)) ?
523
+ '' : ' -e "# coding: utf-8"'
524
+
525
+ unless options[:enable_gems]
526
+ @rubyopt += " --disable-gems" unless @rubyopt.match("--disable-gems")
527
+ end
528
+
529
+ ruby_code = ""
530
+ if options[:encryption_key]
531
+ require "digest/sha2"
532
+ @encryption_key = Digest::SHA2.hexdigest(options[:encryption_key])
533
+ ruby_code = "Neri.key='#{@encryption_key}';"
534
+ end
535
+ if options[:data_file]
536
+ data_file = "%~dp0#{options[:system_dir]}#{File::ALT_SEPARATOR || File::SEPARATOR}#{options[:data_file]}"
537
+ ruby_code += "Neri.datafile='#{data_file}';"
538
+ ruby_code += "load '#{File.basename(@data_files.first)}'"
539
+ else
540
+ ruby_code += "load '%~dp0#{options[:system_dir]}#{File::ALT_SEPARATOR}#{File.basename(@data_files.first)}'"
541
+ end
542
+
543
+ pause_code = ""
544
+ if options[:pause_last]
545
+ if options[:pause_text]
546
+ pause_code = "echo.\necho #{options[:pause_text]}\npause > nul"
547
+ else
548
+ pause_code = "echo.\npause"
549
+ end
550
+ end
551
+
552
+ r = " -rneri"
553
+ r += " -rneri/dxruby" if @use_dxruby
554
+ r += " -rneri/dxruby_tiled" if @use_dxruby_tiled
555
+ r += " -rneri/ayame" if @use_ayame
556
+
557
+ open(batchfile, "w:#{Encoding.default_external.name}") do |f|
558
+ f.puts <<-EOF
559
+ @echo off
560
+ setlocal
561
+ set PATH=%~dp0#{options[:system_dir]}\\#{relative_path(bindir)};%PATH%
562
+ #{options[:chdir_first] ? 'cd /d "%~dp0"' : ''}
563
+ if %~x0 == .exe ( shift )
564
+ #{relative_path(rubyexe, bindir)}#{r} #{@rubyopt}#{enc} -e "#{ruby_code}" %1 %2 %3 %4 %5 %6 %7 %8 %9
565
+ #{pause_code}
566
+ endlocal
567
+ EOF
568
+ end
569
+ end
570
+
571
+
572
+ def create_datafile()
573
+ nputs "Creating data_file '#{datafile}'."
574
+ data_files = @data_files.select { |file| File.file? file }
575
+ @data_files.select { |file| File.directory? file }.each do |dir|
576
+ data_files += Dir.glob(dir + "/**/*").select { |file| File.file? file }
577
+ end
578
+ Neri.key = @encryption_key || "0" * 64
579
+ open(datafile, "wb") do |f|
580
+ pos = 0
581
+ files_str = data_files.map{|file|
582
+ filename = File.expand_path(file)
583
+ filename = relative_path(filename, rubydir, "*neri*" + File::SEPARATOR)
584
+ filename = relative_path(filename, Dir.pwd)
585
+ filedata = [filename, File.size(file), pos]
586
+ pos += File.size(file)
587
+ pos += BLOCK_LENGTH - pos % BLOCK_LENGTH unless pos % BLOCK_LENGTH == 0
588
+ nputs_v " - #{filename}:#{File.size(file)} bytes"
589
+ filedata.join("\t")
590
+ }.join("\n").encode(Encoding::UTF_8)
591
+
592
+ f.write(sprintf("%#{BLOCK_LENGTH}d", files_str.bytesize))
593
+ f.write(xor(files_str))
594
+ data_files.each do |file|
595
+ f.write(xor(File.binread(file)))
596
+ end
597
+ end
598
+ end
599
+
600
+
601
+ def bat_to_exe_converter()
602
+ exefile = batchfile.sub(/\.bat$/, ".exe")
603
+ nputs "Creating exe_file '#{exefile}'."
604
+ File.delete(exefile) if File.exist?(exefile)
605
+ args = %[ /bat "#{batchfile}" /exe "#{exefile}"]
606
+ if options[:b2ec][:x64] == nil
607
+ options[:b2ec][:x64] = true if RbConfig::CONFIG["target"].to_s.index("64")
608
+ end
609
+
610
+ args += options[:b2ec].map{|key, value|
611
+ case value
612
+ when String; %[ /#{key.to_s.tr('_', '-')} "#{value}"]
613
+ when true; %[ /#{key.to_s.tr('_', '-')}]
614
+ else; %[]
615
+ end
616
+ }.join("")
617
+ begin
618
+ exec = %(#{options[:b2ec_path]}#{args})
619
+ nputs_v exec
620
+ options[:quiet] ? `#{exec}` : system(exec)
621
+ rescue SystemCallError
622
+ end
623
+ if File.exist?(exefile)
624
+ File.delete(batchfile)
625
+ else
626
+ nputs "Failed to create exe_file."
627
+ end
628
+ end
629
+
630
+
631
+ def upx()
632
+ nputs "Compressing with UPX."
633
+ options[:upx_targets].each do |target|
634
+ Dir.glob(File.join(options[:output_dir], options[:system_dir], target)).each do |target_path|
635
+ exec = %(#{options[:upx_path]} #{options[:upx_options]} "#{target_path}")
636
+ nputs_v exec
637
+ options[:quiet] ? `#{exec}` : system(exec)
638
+ end
639
+ end
640
+ end
641
+
642
+
643
+ def create_zipfile()
644
+ nputs "Creating zip_file '#{options[:zipfile]}'."
645
+ File.delete(options[:zipfile]) if File.exist?(options[:zipfile])
646
+ exec = %(#{options[:sevenzip_path]} a #{options[:zipfile]} "#{options[:output_dir]}")
647
+ nputs_v exec
648
+ options[:quiet] ? `#{exec}` : system(exec)
649
+ end
650
+
651
+
652
+ def inno_setup()
653
+ filename = options[:inno_script]
654
+ script = "[Setup]\n"
655
+ if File.exist?(filename)
656
+ script = File.read(filename, encoding: Encoding::UTF_8)
657
+ filename = File.basename(filename, ".*") + "_tmp" + File.extname(filename)
658
+ end
659
+
660
+ version = options[:b2ec][:productversion] || options[:b2ec][:fileversion]
661
+ if !script.match(/^AppName=/) && options[:b2ec][:productname]
662
+ script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppName=#{options[:b2ec][:productname]}#{$2}" }
663
+ end
664
+ if !script.match(/^AppVersion=/) && version
665
+ script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppVersion=#{version}#{$2}" }
666
+ end
667
+ if !script.match(/^AppVerName=/) && options[:b2ec][:productname] && version
668
+ script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppVerName=#{options[:b2ec][:productname]} #{version}#{$2}" }
669
+ end
670
+ if !script.match(/^AppPublisher=/) && options[:b2ec][:company]
671
+ script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppPublisher=#{options[:b2ec][:company]}#{$2}" }
672
+ end
673
+ if !script.match(/^AppCopyright=/) && options[:b2ec][:copyright]
674
+ script.sub!(/^(\[Setup\])(\s+)/i){ "#{$1}\nAppCopyright=#{options[:b2ec][:copyright]}#{$2}" }
675
+ end
676
+
677
+ script += "\n[Files]\n" unless script.match(/^\[Files\]/)
678
+ dir = File.expand_path(options[:output_dir])
679
+ files_str = ""
680
+ Dir.glob(File.join(dir, "**", "*")).each do |file|
681
+ next unless File.file? file
682
+ dist_dir = to_winpath(File::SEPARATOR + File.dirname(relative_path(file, dir)))
683
+ dist_dir = "" if dist_dir == "\\."
684
+ files_str += "\nSource: \"#{to_winpath(file)}\"; DistDir: \"{app}#{dist_dir}\""
685
+ files_str += "; Flags: isreadme" if File.basename(file).match(/^readme/i)
686
+ end
687
+ script.sub!(/^(\[Files\])(\s*)/i){ "#{$1}#{files_str}#{$2}" }
688
+
689
+ File.write(filename, script)
690
+ exec = %(#{options[:iscc_path]} "#{filename}")
691
+ nputs_v exec
692
+ options[:quiet] ? `#{exec}` : system(exec)
693
+ end
694
+
695
+ def run()
696
+ check_options
697
+ dependencies = check_dependencies
698
+ copy_files(dependencies)
699
+ create_batch
700
+ create_datafile if options[:data_file]
701
+ bat_to_exe_converter unless options[:no_exe]
702
+ upx if options[:use_upx]
703
+ create_zipfile if options[:zipfile]
704
+ inno_setup if options[:inno_script]
705
+ nputs "Neri Finished."
706
+ end
707
+
708
+ private
709
+
710
+ def nputs(str)
711
+ puts "=== #{str}" unless options[:quiet]
712
+ end
713
+
714
+ def nputs_v(str)
715
+ puts str if options[:verbose]
716
+ end
717
+ end
718
+ end