reflex-packager 0.2.0 → 0.3.0
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 +4 -4
- data/.github/workflows/package.yml +310 -0
- data/.github/workflows/release-gem.yml +2 -49
- data/.github/workflows/tag.yml +11 -28
- data/.github/workflows/test.yml +16 -37
- data/.gitignore +2 -0
- data/ChangeLog.md +28 -0
- data/Gemfile.lock +26 -0
- data/README.md +232 -27
- data/Rakefile +21 -0
- data/VERSION +1 -1
- data/bin/reflex +2 -32
- data/examples/hello/icon.png +0 -0
- data/examples/hello/main.rb +18 -0
- data/examples/hello/reflex.yml +3 -0
- data/lib/reflex/packager/app_store_connect.rb +162 -0
- data/lib/reflex/packager/cli.rb +42 -9
- data/lib/reflex/packager/config.rb +233 -36
- data/lib/reflex/packager/data_compiler.rb +59 -0
- data/lib/reflex/packager/data_file.rb +183 -0
- data/lib/reflex/packager/data_loader.rb +127 -0
- data/lib/reflex/packager/gems.rb +282 -0
- data/lib/reflex/packager/library.rb +120 -0
- data/lib/reflex/packager/macos.rb +592 -94
- data/lib/reflex/packager/platform.rb +289 -10
- data/lib/reflex/packager/profile.rb +38 -26
- data/lib/reflex/packager/profiles/reflex.rb +43 -0
- data/lib/reflex/packager/rake.rb +115 -0
- data/lib/reflex/packager/stores/app_store.rb +60 -0
- data/lib/reflex/packager/stores/itchio.rb +53 -0
- data/lib/reflex/packager/templates/macos/AppStore.entitlements.erb +8 -0
- data/lib/reflex/packager/templates/macos/AppStoreExportOptions.plist.erb +14 -0
- data/lib/reflex/packager/templates/macos/ExportOptions.plist.erb +20 -0
- data/lib/reflex/packager/templates/macos/InfoPlist.strings.erb +5 -0
- data/lib/reflex/packager/templates/macos/boot.rb.erb +29 -0
- data/lib/reflex/packager/templates/macos/compile.rb.erb +7 -0
- data/lib/reflex/packager/templates/macos/main.mm.erb +10 -7
- data/lib/reflex/packager/templates/macos/project.yml.erb +60 -3
- data/lib/reflex/packager/templates/windows/app.manifest.erb +25 -0
- data/lib/reflex/packager/templates/windows/app.rc.erb +38 -0
- data/lib/reflex/packager/templates/windows/boot.rb.erb +32 -0
- data/lib/reflex/packager/templates/windows/main.cpp.erb +47 -0
- data/lib/reflex/packager/templates/windows/runtime.manifest.erb +7 -0
- data/lib/reflex/packager/windows.rb +370 -0
- data/lib/reflex/packager.rb +18 -1
- data/reflex-packager.gemspec +8 -7
- data/test/helper.rb +50 -5
- data/test/test_packager_app_store_connect.rb +108 -0
- data/test/test_packager_cli.rb +38 -3
- data/test/test_packager_config.rb +166 -27
- data/test/test_packager_data_file.rb +96 -0
- data/test/test_packager_data_loader.rb +114 -0
- data/test/test_packager_library.rb +81 -0
- data/test/test_packager_macos.rb +714 -86
- data/test/test_packager_platform.rb +16 -0
- data/test/test_packager_rake.rb +165 -0
- data/test/test_packager_stores_app_store.rb +66 -0
- data/test/test_packager_stores_itchio.rb +38 -0
- data/test/test_packager_windows.rb +685 -0
- metadata +72 -15
- data/.github/workflows/utils.rb +0 -127
- data/lib/reflex/packager/templates/macos/Podfile.erb +0 -30
|
@@ -10,13 +10,15 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
10
10
|
|
|
11
11
|
MAIN = File.basename(__FILE__)
|
|
12
12
|
|
|
13
|
-
def config(dir: __dir__, main: nil, parent: nil, stderr: nil, **hash)
|
|
13
|
+
def config(dir: __dir__, main: nil, parent: nil, stderr: nil, env: {}, **hash)
|
|
14
14
|
main ||= MAIN
|
|
15
|
-
|
|
15
|
+
with_env(ENV_TO_SIGN.merge env) do
|
|
16
|
+
Config.new TEST_PROFILE, dir, {main: main, **hash}, stderr: stderr
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def load_config(dir, path = nil)
|
|
19
|
-
Config.load TEST_PROFILE, dir, path
|
|
21
|
+
with_env(ENV_TO_SIGN) {Config.load TEST_PROFILE, dir, path}
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def stderr()
|
|
@@ -73,11 +75,11 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
73
75
|
main: app.rb
|
|
74
76
|
icon: icon.png
|
|
75
77
|
files: ['*.rb', data]
|
|
76
|
-
pods:
|
|
77
|
-
reflex: {git: https://example.com/reflex, tag: v1}
|
|
78
78
|
macos:
|
|
79
79
|
deployment_target: '12.0'
|
|
80
80
|
archs: [arm64, x86_64]
|
|
81
|
+
cruby: 4.0.600
|
|
82
|
+
category: public.app-category.games
|
|
81
83
|
codesign: {identity: Developer ID, team_id: ABCDE12345}
|
|
82
84
|
YAML
|
|
83
85
|
touch 'icon.png'
|
|
@@ -90,10 +92,11 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
90
92
|
assert_equal 'app.rb', c.main
|
|
91
93
|
assert_equal 'icon.png', c.icon
|
|
92
94
|
assert_equal %w[*.rb data], c.files
|
|
93
|
-
assert_equal %w[1.rb app.rb data],
|
|
94
|
-
assert_equal({git: 'https://example.com/reflex', tag: 'v1'}, c.pods[:reflex])
|
|
95
|
+
assert_equal %w[1.rb app.rb data/2.json], c.app_files
|
|
95
96
|
assert_equal '12.0', c.macos.deployment_target
|
|
96
97
|
assert_equal %w[arm64 x86_64], c.macos.archs
|
|
98
|
+
assert_equal '4.0.600', c.macos.cruby
|
|
99
|
+
assert_equal 'public.app-category.games', c.macos.category
|
|
97
100
|
assert_equal 'Developer ID', c.macos.codesign_identity
|
|
98
101
|
assert_equal 'ABCDE12345', c.macos.codesign_team_id
|
|
99
102
|
end
|
|
@@ -103,6 +106,10 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
103
106
|
assert_equal 'test', config() .name
|
|
104
107
|
assert_equal '1', config(name: 1) .name
|
|
105
108
|
assert_equal 'test', config(name: nil).name
|
|
109
|
+
assert_raise(RP::Error) {config name: '', bundle_id: 'a.b'}
|
|
110
|
+
assert_raise(RP::Error) {config name: ' ', bundle_id: 'a.b'}
|
|
111
|
+
assert_raise(RP::Error) {config name: 'A/B', bundle_id: 'a.b'}
|
|
112
|
+
assert_raise(RP::Error) {config name: 'A:B', bundle_id: 'a.b'}
|
|
106
113
|
end
|
|
107
114
|
|
|
108
115
|
def test_bundle_id()
|
|
@@ -121,7 +128,63 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
121
128
|
assert_equal '1', config(version: '1') .version
|
|
122
129
|
assert_equal '2.3', config(version: '2.3').version
|
|
123
130
|
assert_equal '0.1.0', config(version: nil) .version
|
|
131
|
+
assert_equal '1', config(version: 1) .version
|
|
124
132
|
assert_raise(RP::Error) {config version: '4.'}
|
|
133
|
+
assert_raise(RP::Error) {config version: '2.3beta'}
|
|
134
|
+
assert_raise(RP::Error) {config version: 1.10} # read as 1.1
|
|
135
|
+
|
|
136
|
+
# the VERSION file of the app, which the config comes before
|
|
137
|
+
tmpdir do |dir|
|
|
138
|
+
assert_equal '0.1.0', load_config(dir).version
|
|
139
|
+
File.write 'VERSION', "1.2.3\n"
|
|
140
|
+
assert_equal '1.2.3', load_config(dir).version
|
|
141
|
+
File.binwrite 'VERSION', "\xEF\xBB\xBF1.2.4\r\n" # with a BOM
|
|
142
|
+
assert_equal '1.2.4', load_config(dir).version
|
|
143
|
+
File.write 'reflex.yaml', "version: '4.5'"
|
|
144
|
+
assert_equal '4.5', load_config(dir).version
|
|
145
|
+
end
|
|
146
|
+
tmpdir do |dir|
|
|
147
|
+
File.write 'VERSION', '1.2.3beta'
|
|
148
|
+
error = assert_raise(RP::Error) {load_config dir}
|
|
149
|
+
assert_include error.message, 'VERSION file'
|
|
150
|
+
File.write 'reflex.yaml', "version: '4.5'"
|
|
151
|
+
assert_equal '4.5', load_config(dir).version # the file not read
|
|
152
|
+
end
|
|
153
|
+
assert_not_include assert_raise(RP::Error) {config version: '2.3beta'}.message, 'VERSION file'
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_copyright()
|
|
157
|
+
assert_nil config() .copyright
|
|
158
|
+
assert_equal '© 2026 Me', config(copyright: '© 2026 Me').copyright
|
|
159
|
+
assert_equal '2026', config(copyright: 2026) .copyright
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_localizations()
|
|
163
|
+
assert_equal({'en' => {name: 'test', copyright: nil}}, config.localizations)
|
|
164
|
+
|
|
165
|
+
l10n = config(copyright: 'C', localizations: {ja: {name: 'Tesuto'}, 'zh-Hans': nil}).localizations
|
|
166
|
+
assert_equal %w[en ja zh-Hans], l10n.keys
|
|
167
|
+
assert_equal({name: 'test', copyright: 'C'}, l10n['en'])
|
|
168
|
+
assert_equal({name: 'Tesuto', copyright: 'C'}, l10n['ja'])
|
|
169
|
+
assert_equal({name: 'test', copyright: 'C'}, l10n['zh-Hans'])
|
|
170
|
+
assert_equal({name: '1', copyright: nil}, config(localizations: {ja: {name: 1}}).localizations['ja'])
|
|
171
|
+
|
|
172
|
+
assert_raise(RP::Error) {config localizations: 1}
|
|
173
|
+
assert_raise(RP::Error) {config localizations: {ja: 1}}
|
|
174
|
+
assert_raise(RP::Error) {config localizations: {ja: {name: {}}}}
|
|
175
|
+
assert_raise(RP::Error) {config localizations: {en: {name: 'Test'}}} # the values out of it
|
|
176
|
+
assert_raise(RP::Error) {config localizations: {Japanese: {name: 'Tesuto'}}}
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_display_and_build_versions()
|
|
180
|
+
[
|
|
181
|
+
[{version: '1.2.3'}, '1.2.3', '1.2.3'],
|
|
182
|
+
[{version: '1.2.3.4'}, '1.2.3', '1.2.3.4'],
|
|
183
|
+
[{version: '2.3'}, '2.3', '2.3'],
|
|
184
|
+
].each do |hash, display, build|
|
|
185
|
+
c = config(**hash)
|
|
186
|
+
assert_equal [display, build], [c.display_version, c.build_version], hash.inspect
|
|
187
|
+
end
|
|
125
188
|
end
|
|
126
189
|
|
|
127
190
|
def test_main()
|
|
@@ -142,12 +205,17 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
142
205
|
assert_equal %w[a b], config(files: %w[a b]) .files
|
|
143
206
|
end
|
|
144
207
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
assert_equal
|
|
148
|
-
assert_equal
|
|
149
|
-
|
|
150
|
-
|
|
208
|
+
def test_excludes()
|
|
209
|
+
assert_nil config() .excludes
|
|
210
|
+
assert_equal %w[helper.rb], config(excludes: 'helper.rb').excludes
|
|
211
|
+
assert_equal %w[a b], config(excludes: %w[a b]) .excludes
|
|
212
|
+
assert_raise(RP::Error) {config excludes: {a: 1}}
|
|
213
|
+
assert_raise(RP::Error) {config excludes: [{a: 1}]}
|
|
214
|
+
assert_raise(RP::Error) {config excludes: [%w[a]]}
|
|
215
|
+
assert_raise(RP::Error) {config excludes: [nil]}
|
|
216
|
+
assert_raise(RP::Error) {config excludes: ['']}
|
|
217
|
+
assert_raise(RP::Error) {config excludes: MAIN}
|
|
218
|
+
assert_raise(RP::Error) {config excludes: "./#{MAIN}"}
|
|
151
219
|
end
|
|
152
220
|
|
|
153
221
|
def test_app_files()
|
|
@@ -162,12 +230,32 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
162
230
|
end
|
|
163
231
|
|
|
164
232
|
tmpdir yaml: "files: ['*']" do |dir|
|
|
165
|
-
%w[build dist].each {Dir.mkdir _1}
|
|
166
|
-
touch 'build/1.rb'
|
|
233
|
+
%w[.build dist].each {Dir.mkdir _1}
|
|
234
|
+
touch '.build/1.rb'
|
|
167
235
|
touch 'dist/2.rb'
|
|
168
236
|
assert_equal %w[main.rb], load_config(dir).app_files
|
|
169
237
|
end
|
|
170
238
|
|
|
239
|
+
tmpdir yaml: "files: ['lib/**/*', res]\nexcludes: [lib/a/debug.rb, 'res/*.wav']" do |dir|
|
|
240
|
+
%w[lib/a/b.rb lib/a/debug.rb res/c.png res/d.wav].each {touch _1}
|
|
241
|
+
assert_equal %w[lib/a/b.rb main.rb res/c.png], load_config(dir).app_files
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
tmpdir yaml: "files: [lib, ./res]\nexcludes: [./lib/a/debug.rb, res/d.wav]" do |dir|
|
|
245
|
+
%w[lib/a/b.rb lib/a/debug.rb res/c.png res/d.wav].each {touch _1}
|
|
246
|
+
assert_equal %w[lib/a/b.rb main.rb res/c.png], load_config(dir).app_files
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
tmpdir yaml: "files: ['*']" do |dir|
|
|
250
|
+
touch 'a[1]/b.png'
|
|
251
|
+
assert_equal %w[a[1]/b.png main.rb], load_config(dir).app_files
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
tmpdir yaml: "files: [res, res/.b]" do |dir|
|
|
255
|
+
%w[res/.a res/.b res/.c/d res/e].each {touch _1}
|
|
256
|
+
assert_equal %w[main.rb res/.b res/e], load_config(dir).app_files
|
|
257
|
+
end
|
|
258
|
+
|
|
171
259
|
tmpdir yaml_path: 'a.yaml', yaml: <<~YAML, main_path: 'b.rb' do |dir|
|
|
172
260
|
main: b.rb
|
|
173
261
|
files: '*'
|
|
@@ -188,15 +276,35 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
188
276
|
end
|
|
189
277
|
|
|
190
278
|
def test_macos_archs()
|
|
191
|
-
assert_equal [
|
|
192
|
-
assert_equal [
|
|
193
|
-
assert_equal ['
|
|
194
|
-
assert_equal ['
|
|
195
|
-
assert_equal ['
|
|
279
|
+
assert_equal %w[arm64 x86_64], config() .macos.archs
|
|
280
|
+
assert_equal %w[arm64 x86_64], config(macos: {}) .macos.archs
|
|
281
|
+
assert_equal ['arm64'], config(macos: {archs: 'arm64'}).macos.archs
|
|
282
|
+
assert_equal ['1'], config(macos: {archs: 1}) .macos.archs
|
|
283
|
+
assert_equal ['2', '3'], config(macos: {archs: [2, 3]}) .macos.archs
|
|
284
|
+
assert_equal %w[arm64 x86_64], config(macos: {archs: nil}) .macos.archs
|
|
196
285
|
assert_raise(RP::Error) {config(macos: {archs: []})}
|
|
197
286
|
assert_raise(RP::Error) {config(macos: {archs: {}})}
|
|
198
287
|
end
|
|
199
288
|
|
|
289
|
+
def test_macos_cruby()
|
|
290
|
+
assert_nil config() .macos.cruby
|
|
291
|
+
assert_nil config(macos: {}) .macos.cruby
|
|
292
|
+
assert_equal '4.0.600', config(macos: {cruby: '4.0.600'}) .macos.cruby
|
|
293
|
+
assert_equal '../cruby', config(macos: {cruby: '../cruby'}) .macos.cruby
|
|
294
|
+
assert_raise(RP::Error) {config(macos: {cruby: {}})}
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def test_macos_category()
|
|
298
|
+
assert_nil config() .macos.category
|
|
299
|
+
assert_nil config(macos: {}) .macos.category
|
|
300
|
+
assert_nil config(macos: {category: nil}) .macos.category
|
|
301
|
+
assert_equal 'public.app-category.sports-games',
|
|
302
|
+
config(macos: {category: 'public.app-category.sports-games'}).macos.category
|
|
303
|
+
assert_raise(RP::Error) {config(macos: {category: 'games'})}
|
|
304
|
+
assert_raise(RP::Error) {config(macos: {category: 'public.app-category.Games'})}
|
|
305
|
+
assert_raise(RP::Error) {config(macos: {category: {}})}
|
|
306
|
+
end
|
|
307
|
+
|
|
200
308
|
def test_macos_codesign_identity()
|
|
201
309
|
assert_equal '-', config() .macos.codesign_identity
|
|
202
310
|
assert_equal '-', config(macos: {}) .macos.codesign_identity
|
|
@@ -206,6 +314,9 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
206
314
|
assert_equal '-', config(macos: {codesign: {identity: nil}}).macos.codesign_identity
|
|
207
315
|
assert_raise(RP::Error) {config(macos: {codesign: 2})}
|
|
208
316
|
assert_raise(RP::Error) {config(macos: {codesign: {identity: {}}})}
|
|
317
|
+
|
|
318
|
+
assert_equal 'ID', config(macos: {codesign: {identity: 1}}, env: {'APPLE_CODESIGN_IDENTITY' => 'ID'}).macos.codesign_identity
|
|
319
|
+
assert_equal '1', config(macos: {codesign: {identity: 1}}, env: {'APPLE_CODESIGN_IDENTITY' => ''}) .macos.codesign_identity
|
|
209
320
|
end
|
|
210
321
|
|
|
211
322
|
def test_macos_codesign_team_id()
|
|
@@ -217,24 +328,52 @@ class TestPackagerConfig < Test::Unit::TestCase
|
|
|
217
328
|
assert_nil config(macos: {codesign: {team_id: nil}}).macos.codesign_team_id
|
|
218
329
|
assert_raise(RP::Error) {config(macos: {codesign: 2})}
|
|
219
330
|
assert_raise(RP::Error) {config(macos: {codesign: {team_id: {}}})}
|
|
331
|
+
|
|
332
|
+
assert_equal 'ID', config(macos: {codesign: {team_id: 1}}, env: {'APPLE_TEAM_ID' => 'ID'}).macos.codesign_team_id
|
|
333
|
+
assert_equal '1', config(macos: {codesign: {team_id: 1}}, env: {'APPLE_TEAM_ID' => ''}) .macos.codesign_team_id
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def test_windows_console()
|
|
337
|
+
assert_equal false, config() .windows.console?
|
|
338
|
+
assert_equal false, config(windows: {}) .windows.console?
|
|
339
|
+
assert_equal false, config(windows: nil) .windows.console?
|
|
340
|
+
assert_equal false, config(windows: {console: nil}) .windows.console?
|
|
341
|
+
assert_equal true, config(windows: {console: true}) .windows.console?
|
|
342
|
+
assert_equal false, config(windows: {console: false}).windows.console?
|
|
343
|
+
assert_raise(RP::Error) {config(windows: 1)}
|
|
344
|
+
assert_raise(RP::Error) {config(windows: {console: 'yes'})}
|
|
345
|
+
assert_raise(RP::Error) {config(windows: {console: {}})}
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def test_upload_itchio_project()
|
|
349
|
+
assert_nil config() .upload.itchio_project
|
|
350
|
+
assert_nil config(upload: {}) .upload.itchio_project
|
|
351
|
+
assert_nil config(upload: {itchio: {}}) .upload.itchio_project
|
|
352
|
+
assert_equal 'a/b-c_1', config(upload: {itchio: {project: 'a/b-c_1'}}).upload.itchio_project
|
|
353
|
+
assert_raise(RP::Error) {config(upload: {itchio: 'a/b'})}
|
|
354
|
+
assert_raise(RP::Error) {config(upload: {itchio: {project: 'a'}})}
|
|
355
|
+
assert_raise(RP::Error) {config(upload: {itchio: {project: 'a/b/c'}})}
|
|
356
|
+
assert_raise(RP::Error) {config(upload: {itchio: {project: 'A/b'}})} # lower case only
|
|
220
357
|
end
|
|
221
358
|
|
|
222
359
|
def test_warn_unknown_key()
|
|
223
360
|
e = stderr
|
|
224
361
|
|
|
225
|
-
config stderr: e,
|
|
226
|
-
assert_equal "unknown key '/k1'",
|
|
362
|
+
config stderr: e, k1: 1
|
|
363
|
+
assert_equal "unknown key '/k1'", e.shift
|
|
364
|
+
|
|
365
|
+
config stderr: e, macos: {k2: 2}
|
|
366
|
+
assert_equal "unknown key '/macos/k2'", e.shift
|
|
227
367
|
|
|
228
|
-
config stderr: e,
|
|
229
|
-
assert_equal "unknown key '/macos/
|
|
368
|
+
config stderr: e, macos: {codesign: {k3: 3}}
|
|
369
|
+
assert_equal "unknown key '/macos/codesign/k3'", e.shift
|
|
230
370
|
|
|
231
|
-
config stderr: e,
|
|
232
|
-
assert_equal "unknown key '/
|
|
371
|
+
config stderr: e, localizations: {ja: {k4: 4}}
|
|
372
|
+
assert_equal "unknown key '/localizations/ja/k4'", e.shift
|
|
233
373
|
end
|
|
234
374
|
|
|
235
375
|
def test_invalid_value_type()
|
|
236
376
|
assert_raise(RP::Error) {config macos: 'arm64'}
|
|
237
|
-
assert_raise(RP::Error) {config pods: ['cruby']}
|
|
238
377
|
end
|
|
239
378
|
|
|
240
379
|
end# TestPackagerConfig
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerDataFile < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
DataFile = RP::DataFile
|
|
8
|
+
|
|
9
|
+
def data_file(files, **options, &block)
|
|
10
|
+
Dir.mktmpdir do |dir|
|
|
11
|
+
path = File.join dir, 'data.bin'
|
|
12
|
+
DataFile.write path, files, **options
|
|
13
|
+
block.call path
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_write_and_read()
|
|
18
|
+
files = {
|
|
19
|
+
'main.rb' => 'puts :hello',
|
|
20
|
+
'data/日本語.txt' => 'テキスト',
|
|
21
|
+
'data/bytes.bin' => (0..255).map(&:chr).join.b,
|
|
22
|
+
'data/empty.txt' => ''
|
|
23
|
+
}
|
|
24
|
+
data_file files do |path|
|
|
25
|
+
DataFile.open path do |data|
|
|
26
|
+
assert_equal files.keys, data.names
|
|
27
|
+
files.each do |name, bytes|
|
|
28
|
+
assert_equal bytes.b, data.read(name), name
|
|
29
|
+
assert_equal bytes.bytesize, data.size(name)
|
|
30
|
+
assert_include data.names, name
|
|
31
|
+
end
|
|
32
|
+
assert_nil data.read('none.rb')
|
|
33
|
+
assert_nil data.size('none.rb')
|
|
34
|
+
assert_false data.include?('none.rb')
|
|
35
|
+
assert_true data.include?('main.rb')
|
|
36
|
+
end
|
|
37
|
+
raw = File.binread path
|
|
38
|
+
assert_equal 'RXDF', raw[0, 4] # the header as it is
|
|
39
|
+
assert_not_include raw, 'puts :hello'
|
|
40
|
+
assert_not_include raw, 'main.rb'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# a random seed for each
|
|
44
|
+
raws = 2.times.map {data_file(files) {File.binread _1}}
|
|
45
|
+
assert_not_equal raws[0], raws[1]
|
|
46
|
+
data_file(files, seed: 1) {|path| DataFile.open(path) {assert_equal 'puts :hello', _1.read('main.rb')}}
|
|
47
|
+
|
|
48
|
+
data_file({}) {|path| DataFile.open(path) {assert_empty _1.names}}
|
|
49
|
+
|
|
50
|
+
assert_raise(ArgumentError) {data_file("a\tb" => '') {}}
|
|
51
|
+
assert_raise(ArgumentError) {data_file("a\nb" => '') {}}
|
|
52
|
+
assert_raise(ArgumentError) {data_file('../a' => '') {}}
|
|
53
|
+
assert_raise(ArgumentError) {data_file('a/../../b' => '') {}}
|
|
54
|
+
assert_raise(ArgumentError) {data_file('/a' => '') {}}
|
|
55
|
+
|
|
56
|
+
Dir.mktmpdir do |dir|
|
|
57
|
+
path = File.join dir, 'data.bin'
|
|
58
|
+
assert_raise(ArgumentError) {DataFile.write path, files, seed: 0}
|
|
59
|
+
assert_false File.exist?(path) # not written at all
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_encode()
|
|
64
|
+
bytes = (0..255).map(&:chr).join.b
|
|
65
|
+
encoded = DataFile.encode bytes, 0x7f4a7c15
|
|
66
|
+
assert_equal bytes, encoded.bytes.sort.pack('C*') # each byte once
|
|
67
|
+
assert_equal bytes, DataFile.decode(encoded, 0x7f4a7c15)
|
|
68
|
+
assert_not_equal bytes, encoded
|
|
69
|
+
assert_not_equal bytes.reverse, encoded # not inverted
|
|
70
|
+
assert_not_equal encoded, DataFile.encode(bytes, 0x7f4a7c16)
|
|
71
|
+
assert_equal '89e68061414636a9', encoded.unpack1('H16') # the same on any Ruby
|
|
72
|
+
|
|
73
|
+
assert_raise(ArgumentError) {DataFile.encode bytes, 0}
|
|
74
|
+
assert_raise(ArgumentError) {DataFile.encode bytes, 0x100000000}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_not_a_data_file()
|
|
78
|
+
Dir.mktmpdir do |dir|
|
|
79
|
+
path = File.join dir, 'data.bin'
|
|
80
|
+
File.write path, 'not a data file'
|
|
81
|
+
assert_raise(RuntimeError) {DataFile.new path}
|
|
82
|
+
File.write path, ''
|
|
83
|
+
assert_raise(RuntimeError) {DataFile.new path}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_requires_nothing()
|
|
88
|
+
# a package carries the file to read its data file
|
|
89
|
+
path = File.expand_path '../lib/reflex/packager/data_file.rb', __dir__
|
|
90
|
+
out = IO.popen(
|
|
91
|
+
[RbConfig.ruby, '--disable-gems', '-e', "load #{path.dump}; p Reflex::Packager::DataFile::VERSION"],
|
|
92
|
+
err: [:child, :out], &:read)
|
|
93
|
+
assert_equal "1\n", out
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end# TestPackagerDataFile
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerDataLoader < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
|
|
8
|
+
LIB_DIR = File.expand_path '../lib/reflex/packager', __dir__
|
|
9
|
+
|
|
10
|
+
APP = {
|
|
11
|
+
'main.rb' => <<~RUBY,
|
|
12
|
+
$log = []
|
|
13
|
+
$log << require('foo')
|
|
14
|
+
$log << require('foo')
|
|
15
|
+
require_relative 'lib/bar'
|
|
16
|
+
load 'once.rb'
|
|
17
|
+
load 'once.rb'
|
|
18
|
+
$log << require('shellwords') # from the files
|
|
19
|
+
$log << [__FILE__, __dir__]
|
|
20
|
+
$log << $LOADED_FEATURES.grep(/\\/(foo|lib\\/ba[rz])\\.rb\\z/).map {File.basename _1}
|
|
21
|
+
p $log
|
|
22
|
+
RUBY
|
|
23
|
+
'foo.rb' => '$log << :foo',
|
|
24
|
+
'lib/bar.rb' => "require_relative 'baz'; $log << [:bar, __FILE__]",
|
|
25
|
+
'lib/baz.rb' => '$log << :baz',
|
|
26
|
+
'once.rb' => '$log << :once',
|
|
27
|
+
'image.png' => "\x89PNG".b
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Packs +files+ as an app, and runs the main script of it in another Ruby,
|
|
31
|
+
# as a package does.
|
|
32
|
+
#
|
|
33
|
+
def run_app(files = APP, ruby_version: nil)
|
|
34
|
+
Dir.mktmpdir do |dir|
|
|
35
|
+
src = File.join dir, 'src'
|
|
36
|
+
dir = File.join dir, 'app'
|
|
37
|
+
files.each do |name, content|
|
|
38
|
+
path = File.join src, name
|
|
39
|
+
FileUtils.mkdir_p File.dirname(path)
|
|
40
|
+
File.binwrite path, content
|
|
41
|
+
end
|
|
42
|
+
RP::Platform.pack_app src, dir
|
|
43
|
+
yield src, dir if block_given?
|
|
44
|
+
if ruby_version
|
|
45
|
+
RP::DataFile.open(File.join dir, 'data.bin') do |data|
|
|
46
|
+
RP::DataFile.write data.path, data.names.to_h {[_1, data.read(_1)]}
|
|
47
|
+
.merge('.ruby-version' => ruby_version)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
script = <<~RUBY
|
|
52
|
+
require #{File.join(LIB_DIR, 'data_loader.rb').dump} # with data_file.rb beside
|
|
53
|
+
Dir.chdir #{dir.dump}
|
|
54
|
+
$LOAD_PATH.unshift Dir.pwd
|
|
55
|
+
Reflex::Packager::DataLoader.setup Dir.pwd
|
|
56
|
+
load 'main.rb'
|
|
57
|
+
RUBY
|
|
58
|
+
IO.popen [RbConfig.ruby, '-e', script], err: [:child, :out], &:read
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_pack_app()
|
|
63
|
+
run_app do |src, dir|
|
|
64
|
+
assert_equal APP.keys.sort, Dir.glob('**/*.*', base: src).sort # as they are
|
|
65
|
+
assert_equal %w[data.bin image.png], Dir.children(dir).sort # the others as they are
|
|
66
|
+
assert_equal "\x89PNG".b, File.binread(File.join dir, 'image.png')
|
|
67
|
+
RP::DataFile.open File.join(dir, 'data.bin') do |data|
|
|
68
|
+
assert_equal %w[.ruby-version foo.rbc lib/bar.rbc lib/baz.rbc main.rbc once.rbc],
|
|
69
|
+
data.names.sort
|
|
70
|
+
assert_equal RUBY_VERSION, data.read('.ruby-version')
|
|
71
|
+
assert_not_include data.read('main.rbc'), '$log << require' # compiled
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_require()
|
|
77
|
+
log = eval run_app
|
|
78
|
+
assert_equal [
|
|
79
|
+
:foo, true, false,
|
|
80
|
+
:baz, [:bar, 'lib/bar.rb'],
|
|
81
|
+
:once, :once,
|
|
82
|
+
true,
|
|
83
|
+
['main.rb', '.'],
|
|
84
|
+
%w[foo.rb bar.rb baz.rb] # each before it runs, for one it requires to require it back
|
|
85
|
+
], log
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_files()
|
|
89
|
+
files = {
|
|
90
|
+
'main.rb' => <<~RUBY,
|
|
91
|
+
r = []
|
|
92
|
+
r << File.read('data/a.txt')
|
|
93
|
+
r << Dir.glob('**/*').sort # with none of the scripts
|
|
94
|
+
r << [File.exist?('main.rb'), File.exist?('sub.rb')]
|
|
95
|
+
r << require_relative('sub')
|
|
96
|
+
p r
|
|
97
|
+
RUBY
|
|
98
|
+
'sub.rb' => '',
|
|
99
|
+
'data/a.txt' => 'abc'
|
|
100
|
+
}
|
|
101
|
+
assert_equal [
|
|
102
|
+
'abc',
|
|
103
|
+
%w[data data.bin data/a.txt],
|
|
104
|
+
[false, false],
|
|
105
|
+
true
|
|
106
|
+
], eval(run_app files)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_ruby_version()
|
|
110
|
+
assert_match(/data file is for Ruby 0\.0\.0, not #{Regexp.escape RUBY_VERSION}/,
|
|
111
|
+
run_app(ruby_version: '0.0.0'))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end# TestPackagerDataLoader
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerLibrary < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
|
|
8
|
+
# Makes the gems in a directory and puts their lib/ on the load path, as
|
|
9
|
+
# RUBYLIB does for the gems of a repository being worked on.
|
|
10
|
+
#
|
|
11
|
+
# @param gems [Hash] {dir => [gem name, dependencies, files]}
|
|
12
|
+
#
|
|
13
|
+
def fake_gems(gems, &block)
|
|
14
|
+
Dir.mktmpdir do |root|
|
|
15
|
+
gems.each do |dir, (name, deps, files)|
|
|
16
|
+
FileUtils.mkdir_p File.join(root, dir)
|
|
17
|
+
File.write File.join(root, dir, "#{dir}.gemspec"), <<~GEMSPEC
|
|
18
|
+
Gem::Specification.new do |s|
|
|
19
|
+
s.name = '#{name}'
|
|
20
|
+
s.version = '1.0'
|
|
21
|
+
#{deps.map {"s.add_dependency '#{_1}'"}.join "\n "}
|
|
22
|
+
end
|
|
23
|
+
GEMSPEC
|
|
24
|
+
files.each do |file|
|
|
25
|
+
path = File.join root, dir, file
|
|
26
|
+
FileUtils.mkdir_p File.dirname(path)
|
|
27
|
+
FileUtils.touch path
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
libs = gems.keys.map {File.join root, _1, 'lib'}
|
|
31
|
+
$LOAD_PATH.unshift(*libs)
|
|
32
|
+
block.call root
|
|
33
|
+
ensure
|
|
34
|
+
$LOAD_PATH.replace $LOAD_PATH - libs.to_a
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_collect()
|
|
39
|
+
gems = {
|
|
40
|
+
'fakebase' => [
|
|
41
|
+
'fakebase',
|
|
42
|
+
[],
|
|
43
|
+
%w[lib/fakebase/extension.rb]
|
|
44
|
+
],
|
|
45
|
+
# the name of the gem differs from the one of the library, as reflexion
|
|
46
|
+
'fakenative' => [
|
|
47
|
+
'fakenativeion',
|
|
48
|
+
%w[fakebase],
|
|
49
|
+
%w[lib/fakenative/extension.rb lib/fakenative/ext.rb]
|
|
50
|
+
],
|
|
51
|
+
# not a library, which has no lib/*/extension.rb as reflex-packager
|
|
52
|
+
'faketool' => [
|
|
53
|
+
'faketool',
|
|
54
|
+
%w[fakebase],
|
|
55
|
+
%w[lib/faketool.rb]
|
|
56
|
+
],
|
|
57
|
+
'fakeapp' => [
|
|
58
|
+
'fakeapp',
|
|
59
|
+
%w[faketool fakenativeion no-such-gem],
|
|
60
|
+
%w[lib/fakeapp/extension.rb]
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
fake_gems gems do |root|
|
|
64
|
+
libs = RP::Library.collect File.join(root, 'fakeapp')
|
|
65
|
+
assert_equal %w[fakebase fakenative fakeapp], libs.map(&:name)
|
|
66
|
+
assert_equal [nil, 'fakenative_ext', nil], libs.map(&:extension)
|
|
67
|
+
assert_equal libs.map {File.join root, _1.name}, libs.map(&:root)
|
|
68
|
+
|
|
69
|
+
# leaving out the ones collected already
|
|
70
|
+
libs = RP::Library.collect File.join(root, 'fakeapp'), known: libs.first(1)
|
|
71
|
+
assert_equal %w[fakenative fakeapp], libs.map(&:name)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_collect_the_libraries_of_the_profiles()
|
|
76
|
+
# this repository, which the helper puts on the load path
|
|
77
|
+
assert_equal %w[xot rucy rays reflex], TEST_PROFILE.libraries.map(&:name)
|
|
78
|
+
assert_equal %w[rays_ext reflex_ext], TEST_PROFILE.extensions
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end# TestPackagerLibrary
|