Skip to content

Commit 1e92e6c

Browse files
committed
file_packager.py: Add options struct and split main function. NFC
This change is a cleanup and refactor in preparation for moving to wasm-embedded file data.
1 parent 9017163 commit 1e92e6c

File tree

1 file changed

+106
-92
lines changed

1 file changed

+106
-92
lines changed

tools/file_packager.py

Lines changed: 106 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -163,70 +163,77 @@ def add(mode, rootpathsrc, rootpathdst):
163163
dirnames.extend(new_dirnames)
164164

165165

166+
class Options:
167+
def __init__(self):
168+
self.export_name = 'Module'
169+
self.has_preloaded = False
170+
self.jsoutput = None
171+
self.from_emcc = False
172+
self.force = True
173+
# If set to True, IndexedDB (IDBFS in library_idbfs.js) is used to locally
174+
# cache VFS XHR so that subsequent page loads can read the data from the
175+
# offline cache instead.
176+
self.use_preload_cache = False
177+
self.indexeddb_name = 'EM_PRELOAD_CACHE'
178+
# If set to True, the package metadata is stored separately from js-output
179+
# file which makes js-output file immutable to the package content changes.
180+
# If set to False, the package metadata is stored inside the js-output file
181+
# which makes js-output file to mutate on each invocation of this packager tool.
182+
self.separate_metadata = False
183+
self.lz4 = False
184+
self.use_preload_plugins = False
185+
self.support_node = True
186+
187+
188+
options = Options()
189+
190+
166191
def main():
167192
data_files = []
168-
export_name = 'Module'
169-
leading = ''
170-
has_preloaded = False
171193
plugins = []
172-
jsoutput = None
173-
from_emcc = False
174-
force = True
175-
# If set to True, IndexedDB (IDBFS in library_idbfs.js) is used to locally
176-
# cache VFS XHR so that subsequent page loads can read the data from the
177-
# offline cache instead.
178-
use_preload_cache = False
179-
indexeddb_name = 'EM_PRELOAD_CACHE'
180-
# If set to True, the package metadata is stored separately from js-output
181-
# file which makes js-output file immutable to the package content changes.
182-
# If set to False, the package metadata is stored inside the js-output file
183-
# which makes js-output file to mutate on each invocation of this packager tool.
184-
separate_metadata = False
185-
lz4 = False
186-
use_preload_plugins = False
187-
support_node = True
194+
leading = ''
188195

189196
for arg in sys.argv[2:]:
190197
if arg == '--preload':
191-
has_preloaded = True
198+
options.has_preloaded = True
192199
leading = 'preload'
193200
elif arg == '--embed':
194201
leading = 'embed'
195202
elif arg == '--exclude':
196203
leading = 'exclude'
197204
elif arg == '--no-force':
198-
force = False
205+
options.force = False
199206
leading = ''
200207
elif arg == '--use-preload-cache':
201-
use_preload_cache = True
208+
options.use_preload_cache = True
202209
leading = ''
203210
elif arg.startswith('--indexedDB-name'):
204-
indexeddb_name = arg.split('=', 1)[1] if '=' in arg else None
211+
options.indexeddb_name = arg.split('=', 1)[1] if '=' in arg else None
205212
leading = ''
206213
elif arg == '--no-heap-copy':
207214
print('ignoring legacy flag --no-heap-copy (that is the only mode supported now)')
208215
leading = ''
209216
elif arg == '--separate-metadata':
210-
separate_metadata = True
217+
options.separate_metadata = True
211218
leading = ''
212219
elif arg == '--lz4':
213-
lz4 = True
220+
options.lz4 = True
214221
leading = ''
215222
elif arg == '--use-preload-plugins':
216-
use_preload_plugins = True
223+
options.use_preload_plugins = True
217224
leading = ''
218225
elif arg == '--no-node':
219-
support_node = False
226+
options.support_node = False
220227
leading = ''
221228
elif arg.startswith('--js-output'):
222-
jsoutput = arg.split('=', 1)[1] if '=' in arg else None
229+
options.jsoutput = arg.split('=', 1)[1] if '=' in arg else None
223230
leading = ''
224231
elif arg.startswith('--export-name'):
225232
if '=' in arg:
226-
export_name = arg.split('=', 1)[1]
233+
options.export_name = arg.split('=', 1)[1]
227234
leading = ''
228235
elif arg.startswith('--from-emcc'):
229-
from_emcc = True
236+
options.from_emcc = True
230237
leading = ''
231238
elif arg.startswith('--plugin'):
232239
with open(arg.split('=', 1)[1]) as f:
@@ -260,46 +267,23 @@ def main():
260267
print('Unknown parameter:', arg, file=sys.stderr)
261268
return 1
262269

263-
if (not force) and not data_files:
264-
has_preloaded = False
265-
if not has_preloaded or jsoutput is None:
266-
assert not separate_metadata, (
270+
if (not options.force) and not data_files:
271+
options.has_preloaded = False
272+
if not options.has_preloaded or options.jsoutput is None:
273+
assert not options.separate_metadata, (
267274
'cannot separate-metadata without both --preloaded files '
268275
'and a specified --js-output')
269276

270-
if not from_emcc:
277+
if not options.from_emcc:
271278
print('Remember to build the main file with -s FORCE_FILESYSTEM=1 '
272279
'so that it includes support for loading this file package',
273280
file=sys.stderr)
274281

275-
if jsoutput and os.path.abspath(jsoutput) == os.path.abspath(data_target):
282+
if options.jsoutput and os.path.abspath(options.jsoutput) == os.path.abspath(data_target):
276283
print('error: TARGET should not be the same value of --js-output',
277284
file=sys.stderr)
278285
return 1
279286

280-
ret = ''
281-
# emcc will add this to the output itself, so it is only needed for
282-
# standalone calls
283-
if not from_emcc:
284-
ret = '''
285-
var Module = typeof %(EXPORT_NAME)s !== 'undefined' ? %(EXPORT_NAME)s : {};\n''' % {"EXPORT_NAME": export_name}
286-
287-
ret += '''
288-
if (!Module.expectedDataFileDownloads) {
289-
Module.expectedDataFileDownloads = 0;
290-
}
291-
Module.expectedDataFileDownloads++;
292-
(function() {
293-
// When running as a pthread, FS operations are proxied to the main thread, so we don't need to
294-
// fetch the .data bundle on the worker
295-
if (Module['ENVIRONMENT_IS_PTHREAD']) return;
296-
var loadPackage = function(metadata) {\n'''
297-
298-
code = '''
299-
function assert(check, msg) {
300-
if (!check) throw msg + new Error().stack;
301-
}\n'''
302-
303287
for file_ in data_files:
304288
if not should_ignore(file_['srcpath']):
305289
if os.path.isdir(file_['srcpath']):
@@ -377,6 +361,56 @@ def was_seen(name):
377361

378362
metadata = {'files': []}
379363

364+
ret = generate_js(data_files, metadata)
365+
366+
if options.force or len(data_files):
367+
if options.jsoutput is None:
368+
print(ret)
369+
else:
370+
# Overwrite the old jsoutput file (if exists) only when its content
371+
# differs from the current generated one, otherwise leave the file
372+
# untouched preserving its old timestamp
373+
if os.path.isfile(options.jsoutput):
374+
with open(options.jsoutput) as f:
375+
old = f.read()
376+
if old != ret:
377+
with open(options.jsoutput, 'w') as f:
378+
f.write(ret)
379+
else:
380+
with open(options.jsoutput, 'w') as f:
381+
f.write(ret)
382+
if options.separate_metadata:
383+
with open(options.jsoutput + '.metadata', 'w') as f:
384+
json.dump(metadata, f, separators=(',', ':'))
385+
386+
return 0
387+
388+
389+
def generate_js(data_files, metadata):
390+
# emcc will add this to the output itself, so it is only needed for
391+
# standalone calls
392+
if options.from_emcc:
393+
ret = ''
394+
else:
395+
ret = '''
396+
var Module = typeof %(EXPORT_NAME)s !== 'undefined' ? %(EXPORT_NAME)s : {};\n''' % {"EXPORT_NAME": options.export_name}
397+
398+
ret += '''
399+
if (!Module.expectedDataFileDownloads) {
400+
Module.expectedDataFileDownloads = 0;
401+
}
402+
Module.expectedDataFileDownloads++;
403+
(function() {
404+
// When running as a pthread, FS operations are proxied to the main thread, so we don't need to
405+
// fetch the .data bundle on the worker
406+
if (Module['ENVIRONMENT_IS_PTHREAD']) return;
407+
var loadPackage = function(metadata) {\n'''
408+
409+
code = '''
410+
function assert(check, msg) {
411+
if (!check) throw msg + new Error().stack;
412+
}\n'''
413+
380414
# Set up folders
381415
partial_dirs = []
382416
for file_ in data_files:
@@ -391,7 +425,7 @@ def was_seen(name):
391425
% (json.dumps('/' + '/'.join(parts[:i])), json.dumps(parts[i])))
392426
partial_dirs.append(partial)
393427

394-
if has_preloaded:
428+
if options.has_preloaded:
395429
# Bundle all datafiles into one archive. Avoids doing lots of simultaneous
396430
# XHRs which has overhead.
397431
start = 0
@@ -430,7 +464,7 @@ def was_seen(name):
430464
Module['removeRunDependency']('fp ' + that.name);
431465
'''
432466

433-
if not lz4:
467+
if not options.lz4:
434468
# Data requests - for getting a block of data out of the big archive - have
435469
# a similar API to XHRs
436470
code += '''
@@ -462,7 +496,7 @@ def was_seen(name):
462496
var files = metadata['files'];
463497
for (var i = 0; i < files.length; ++i) {
464498
new DataRequest(files[i]['start'], files[i]['end'], files[i]['audio'] || 0).open('GET', files[i]['filename']);
465-
}\n''' % (create_preloaded if use_preload_plugins else create_data)
499+
}\n''' % (create_preloaded if options.use_preload_plugins else create_data)
466500

467501
for (counter, file_) in enumerate(data_files):
468502
filename = file_['dstpath']
@@ -488,8 +522,8 @@ def was_seen(name):
488522
else:
489523
assert 0
490524

491-
if has_preloaded:
492-
if not lz4:
525+
if options.has_preloaded:
526+
if not options.lz4:
493527
# Get the big archive and split it up
494528
use_data = '''
495529
// Reuse the bytearray from the XHR as the source for file reads.
@@ -516,7 +550,7 @@ def was_seen(name):
516550
assert(typeof Module['LZ4'] === 'object', 'LZ4 not present - was your app build with -s LZ4=1 ?');
517551
Module['LZ4'].loadPackage({ 'metadata': metadata, 'compressedData': compressedData }, %s);
518552
Module['removeRunDependency']('datafile_%s');
519-
''' % (meta, "true" if use_preload_plugins else "false", js_manipulation.escape_for_js_string(data_target))
553+
''' % (meta, "true" if options.use_preload_plugins else "false", js_manipulation.escape_for_js_string(data_target))
520554

521555
package_uuid = uuid.uuid4()
522556
package_name = data_target
@@ -546,7 +580,7 @@ def was_seen(name):
546580
var PACKAGE_UUID = metadata['package_uuid'];
547581
'''
548582

549-
if use_preload_cache:
583+
if options.use_preload_cache:
550584
code += r'''
551585
var indexedDB;
552586
if (typeof window === 'object') {
@@ -559,7 +593,7 @@ def was_seen(name):
559593
}
560594
var IDB_RO = "readonly";
561595
var IDB_RW = "readwrite";
562-
var DB_NAME = "''' + indexeddb_name + '''";
596+
var DB_NAME = "''' + options.indexeddb_name + '''";
563597
var DB_VERSION = 1;
564598
var METADATA_STORE_NAME = 'METADATA';
565599
var PACKAGE_STORE_NAME = 'PACKAGES';
@@ -712,7 +746,7 @@ def was_seen(name):
712746

713747
# add Node.js support code, if necessary
714748
node_support_code = ''
715-
if support_node:
749+
if options.support_node:
716750
node_support_code = '''
717751
if (typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string') {
718752
require('fs').readFile(packageName, function(err, contents) {
@@ -793,7 +827,7 @@ def was_seen(name):
793827
code += '''
794828
if (!Module.preloadResults) Module.preloadResults = {};\n'''
795829

796-
if use_preload_cache:
830+
if options.use_preload_cache:
797831
code += '''
798832
function preloadFallback(error) {
799833
console.error(error);
@@ -864,7 +898,7 @@ def was_seen(name):
864898
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
865899
}\n'''
866900

867-
if separate_metadata:
901+
if options.separate_metadata:
868902
_metadata_template = '''
869903
Module['removeRunDependency']('%(metadata_file)s');
870904
}
@@ -888,7 +922,7 @@ def was_seen(name):
888922
} else {
889923
if (!Module['preRun']) Module['preRun'] = [];
890924
Module["preRun"].push(runMetaWithFS);
891-
}\n''' % {'metadata_file': os.path.basename(jsoutput + '.metadata')}
925+
}\n''' % {'metadata_file': os.path.basename(options.jsoutput + '.metadata')}
892926

893927
else:
894928
_metadata_template = '''
@@ -898,27 +932,7 @@ def was_seen(name):
898932
ret += '''%s
899933
})();\n''' % _metadata_template
900934

901-
if force or len(data_files):
902-
if jsoutput is None:
903-
print(ret)
904-
else:
905-
# Overwrite the old jsoutput file (if exists) only when its content
906-
# differs from the current generated one, otherwise leave the file
907-
# untouched preserving its old timestamp
908-
if os.path.isfile(jsoutput):
909-
with open(jsoutput) as f:
910-
old = f.read()
911-
if old != ret:
912-
with open(jsoutput, 'w') as f:
913-
f.write(ret)
914-
else:
915-
with open(jsoutput, 'w') as f:
916-
f.write(ret)
917-
if separate_metadata:
918-
with open(jsoutput + '.metadata', 'w') as f:
919-
json.dump(metadata, f, separators=(',', ':'))
920-
921-
return 0
935+
return ret
922936

923937

924938
if __name__ == '__main__':

0 commit comments

Comments
 (0)