ocran 1.3.15 → 1.3.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+ require "tempfile"
3
+ require_relative "file_path_set"
4
+
5
+ module Ocran
6
+ # Utility class that produces the actual executable. Opcodes
7
+ # (create_file, mkdir etc) are added by invoking methods on an
8
+ # instance of OcranBuilder.
9
+ class StubBuilder
10
+ Signature = [0x41, 0xb6, 0xba, 0x4e].freeze
11
+ OP_END = 0
12
+ OP_CREATE_DIRECTORY = 1
13
+ OP_CREATE_FILE = 2
14
+ OP_SETENV = 3
15
+ OP_SET_SCRIPT = 4
16
+
17
+ DEBUG_MODE = 0x01
18
+ EXTRACT_TO_EXE_DIR = 0x02
19
+ AUTO_CLEAN_INST_DIR = 0x04
20
+ CHDIR_BEFORE_SCRIPT = 0x08
21
+ DATA_COMPRESSED = 0x10
22
+
23
+ base_dir = File.expand_path("../../share/ocran", File.dirname(__FILE__))
24
+ STUB_PATH = File.expand_path("stub.exe", base_dir)
25
+ STUBW_PATH = File.expand_path("stubw.exe", base_dir)
26
+ LZMA_PATH = File.expand_path("lzma.exe", base_dir)
27
+ EDICON_PATH = File.expand_path("edicon.exe", base_dir)
28
+
29
+ attr_reader :data_size
30
+
31
+ # chdir_before:
32
+ # When set to true, the working directory is changed to the application's
33
+ # deployment location at runtime.
34
+ #
35
+ # debug_mode:
36
+ # When the debug_mode option is set to true, the stub will output debug information
37
+ # when the exe file is executed. Debug mode can also be enabled within the directive
38
+ # code using the enable_debug_mode method. This option is provided to transition to
39
+ # debug mode from the initialization point of the stub.
40
+ #
41
+ # debug_extract:
42
+ # When set to true, the runtime file is extracted to the directory where the executable resides,
43
+ # and the extracted files remain even after the application exits.
44
+ # When set to false, the runtime file is extracted to the system's temporary directory,
45
+ # and the extracted files are deleted after the application exits.
46
+ #
47
+ # gui_mode:
48
+ # When set to true, the stub does not display a console window at startup. Errors are shown in a dialog window.
49
+ # When set to false, the stub reports errors through the console window.
50
+ #
51
+ # icon_path:
52
+ # Specifies the path to the icon file to be embedded in the stub's resources.
53
+ #
54
+ def initialize(path, chdir_before: nil, debug_extract: nil, debug_mode: nil,
55
+ enable_compression: nil, gui_mode: nil, icon_path: nil)
56
+ @dirs = FilePathSet.new
57
+ @files = FilePathSet.new
58
+ @data_size = 0
59
+
60
+ if icon_path && !File.exist?(icon_path)
61
+ raise "Icon file #{icon_path} not found"
62
+ end
63
+
64
+ stub = Tempfile.new("", File.dirname(path))
65
+ IO.copy_stream(gui_mode ? STUBW_PATH : STUB_PATH, stub)
66
+ stub.close
67
+
68
+ if icon_path
69
+ system(EDICON_PATH, stub.path, icon_path.to_s, exception: true)
70
+ end
71
+
72
+ File.open(stub, "ab") do |of|
73
+ @of = of
74
+ @opcode_offset = @of.size
75
+
76
+ write_header(debug_mode, debug_extract, chdir_before, enable_compression)
77
+
78
+ b = proc {
79
+ yield(self)
80
+ write_opcode(OP_END)
81
+ }
82
+
83
+ if enable_compression
84
+ compress(&b)
85
+ else
86
+ b.yield
87
+ end
88
+
89
+ write_footer
90
+ end
91
+
92
+ File.rename(stub, path)
93
+ end
94
+
95
+ def mkdir(target)
96
+ return unless @dirs.add?("/", target)
97
+
98
+ write_opcode(OP_CREATE_DIRECTORY)
99
+ write_path(target)
100
+ end
101
+
102
+ def cp(source, target)
103
+ unless File.exist?(source)
104
+ raise "The file does not exist (#{source})"
105
+ end
106
+
107
+ return unless @files.add?(source, target)
108
+
109
+ write_opcode(OP_CREATE_FILE)
110
+ write_path(target)
111
+ write_file(source)
112
+ end
113
+
114
+ # Specifies the final application script to be launched, which can be called
115
+ # from any position in the data stream. It cannot be specified more than once.
116
+ #
117
+ # You can omit setting OP_SET_SCRIPT without issues, in which case
118
+ # the stub terminates without launching anything after performing other
119
+ # runtime operations.
120
+ def exec(image, script, *argv)
121
+ if @script_set
122
+ raise "Script is already set"
123
+ end
124
+ @script_set = true
125
+
126
+ write_opcode(OP_SET_SCRIPT)
127
+ write_string_array(convert_to_native(image), convert_to_native(script), *argv)
128
+ end
129
+
130
+ def export(name, value)
131
+ write_opcode(OP_SETENV)
132
+ write_string(name.to_s)
133
+ write_string(value.to_s)
134
+ end
135
+
136
+ def compress
137
+ IO.popen([LZMA_PATH, "e", "-si", "-so"], "r+b") do |lzma|
138
+ _of, @of = @of, lzma
139
+ Thread.new { yield(self); lzma.close_write }
140
+ IO.copy_stream(lzma, _of)
141
+ @of = _of
142
+ end
143
+
144
+ # Calculate the position to write the LZMA decompressed size (64-bit unsigned integer)
145
+ # @opcode_offset: start position of the data section
146
+ # 1: size of the header byte
147
+ # 5: size of the LZMA header in bytes
148
+ File.binwrite(@of.path, [@data_size].pack("Q<"), @opcode_offset + 1 + 5)
149
+ end
150
+ private :compress
151
+
152
+ def write_header(debug_mode, debug_extract, chdir_before, compressed)
153
+ next_to_exe, delete_after = debug_extract, !debug_extract
154
+ @of << [0 |
155
+ (debug_mode ? DEBUG_MODE : 0) |
156
+ (next_to_exe ? EXTRACT_TO_EXE_DIR : 0) |
157
+ (delete_after ? AUTO_CLEAN_INST_DIR : 0) |
158
+ (chdir_before ? CHDIR_BEFORE_SCRIPT : 0) |
159
+ (compressed ? DATA_COMPRESSED : 0)
160
+ ].pack("C")
161
+ end
162
+ private :write_header
163
+
164
+ def write_opcode(op)
165
+ @of << [op].pack("C")
166
+ @data_size += 1
167
+ end
168
+ private :write_opcode
169
+
170
+ def write_size(i)
171
+ if i > 0xFFFF_FFFF
172
+ raise ArgumentError, "Size #{i} is too large: must be 32-bit unsigned integer (0 to 4294967295)"
173
+ end
174
+
175
+ @of << [i].pack("V")
176
+ @data_size += 4
177
+ end
178
+ private :write_size
179
+
180
+ def write_string(str)
181
+ len = str.bytesize + 1 # +1 to account for the null terminator
182
+
183
+ if len > 0xFFFF
184
+ raise ArgumentError, "String length #{len} is too large: must be less than or equal to 65535 bytes including null terminator"
185
+ end
186
+
187
+ @of << [len, str].pack("vZ*")
188
+ @data_size += 2 + len
189
+ end
190
+ private :write_string
191
+
192
+ def write_string_array(*str_array)
193
+ ary = str_array.map(&:to_s)
194
+ size = ary.sum(0) { |s| s.bytesize + 1 }
195
+ write_size(size)
196
+ ary.each_slice(1) { |a| @of << a.pack("Z*") }
197
+ @data_size += size
198
+ end
199
+ private :write_string_array
200
+
201
+ def write_file(src)
202
+ size = File.size(src)
203
+ write_size(size)
204
+ IO.copy_stream(src, @of)
205
+ @data_size += size
206
+ end
207
+ private :write_file
208
+
209
+ def write_path(path)
210
+ write_string(convert_to_native(path))
211
+ end
212
+ private :write_path
213
+
214
+ def write_footer
215
+ @of << ([@opcode_offset] + Signature).pack("VC*")
216
+ end
217
+ private :write_footer
218
+
219
+ def convert_to_native(path)
220
+ path.to_s.tr(File::SEPARATOR, "\\")
221
+ end
222
+ private :convert_to_native
223
+ end
224
+ end
data/lib/ocran/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ocran
4
- VERSION = "1.3.15"
4
+ VERSION = "1.3.16"
5
5
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ocran
4
+ module WindowsCommandEscaping
5
+ module_function
6
+
7
+ def escape_double_quotes(s)
8
+ s.to_s.gsub('"', '""')
9
+ end
10
+
11
+ def quote_and_escape(s)
12
+ "\"#{escape_double_quotes(s)}\""
13
+ end
14
+ end
15
+ end
data/lib/ocran.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "ocran/version"
4
-
5
3
  module Ocran
4
+ autoload :VERSION, "ocran/version"
5
+
6
+ singleton_class.attr_accessor :option
6
7
  end
Binary file
data/share/ocran/stub.exe CHANGED
Binary file
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocran
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.15
4
+ version: 1.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andi Idogawa
@@ -9,13 +9,13 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-11-30 00:00:00.000000000 Z
12
+ date: 2024-08-05 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: "OCRAN (One-Click Ruby Application Next) builds Windows executables from
15
15
  Ruby source code. \n The executable is a self-extracting, self-running executable
16
16
  that contains the Ruby interpreter, your source code and any additionally needed
17
17
  ruby libraries or DLL.\n \n This is a fork of OCRA that is compatible with ruby
18
- version after 2.6. \n Migration guide: make sure to write ocran instead of ocra
18
+ version after 3.0.\n Migration guide: make sure to write ocran instead of ocra
19
19
  in your code. For instance: OCRAN_EXECUTABLE\n\n usage: \n ocra helloworld.rb\n
20
20
  \ helloworld.exe\n\n See readme at https://github.com/largo/ocran\n Report problems
21
21
  in the github issues. Contributions welcome.\n This gem contains executables. We
@@ -29,9 +29,26 @@ extra_rdoc_files: []
29
29
  files:
30
30
  - bin/ocran
31
31
  - lib/ocran.rb
32
+ - lib/ocran/build_constants.rb
33
+ - lib/ocran/build_facade.rb
34
+ - lib/ocran/build_helper.rb
35
+ - lib/ocran/command_output.rb
36
+ - lib/ocran/direction.rb
37
+ - lib/ocran/empty_source
38
+ - lib/ocran/file_path_set.rb
39
+ - lib/ocran/gem_spec_queryable.rb
40
+ - lib/ocran/host_config_helper.rb
41
+ - lib/ocran/inno_setup_script_builder.rb
42
+ - lib/ocran/launcher_batch_builder.rb
43
+ - lib/ocran/library_detector.rb
44
+ - lib/ocran/option.rb
45
+ - lib/ocran/refine_pathname.rb
46
+ - lib/ocran/runner.rb
47
+ - lib/ocran/runtime_environment.rb
48
+ - lib/ocran/stub_builder.rb
32
49
  - lib/ocran/version.rb
50
+ - lib/ocran/windows_command_escaping.rb
33
51
  - share/ocran/edicon.exe
34
- - share/ocran/empty-msys-2.0.dll
35
52
  - share/ocran/lzma.exe
36
53
  - share/ocran/stub.exe
37
54
  - share/ocran/stubw.exe
@@ -50,14 +67,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
67
  requirements:
51
68
  - - ">="
52
69
  - !ruby/object:Gem::Version
53
- version: 2.6.0
70
+ version: 3.0.0
54
71
  required_rubygems_version: !ruby/object:Gem::Requirement
55
72
  requirements:
56
73
  - - ">="
57
74
  - !ruby/object:Gem::Version
58
75
  version: '0'
59
76
  requirements: []
60
- rubygems_version: 3.4.10
77
+ rubygems_version: 3.5.3
61
78
  signing_key:
62
79
  specification_version: 4
63
80
  summary: OCRAN (One-Click Ruby Application Next) builds Windows executables from Ruby