import argparse
import itertools
import json
import os
import glob
import platform
import re
import shutil
import sys
_HERE_PATH = os.path.dirname(__file__)
_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..', '..'))
_CWD = os.getcwd()
sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'node'))
import node
import node_modules
def _request_list_path(out_folder, target_name):
return os.path.join(out_folder, target_name + '_requestlist.txt')
def _get_dep_path(dep, host_url, out_folder):
if dep.startswith(host_url):
return dep.replace(host_url, os.path.relpath(out_folder, _CWD))
elif not (dep.startswith('chrome://') or dep.startswith('//')):
return os.path.relpath(out_folder, _CWD) + '/' + dep
return dep
def _update_dep_file(in_folder, args, out_file_path, manifest):
in_path = os.path.join(_CWD, in_folder)
request_list = []
for out_file in manifest:
request_list += manifest[out_file]
request_list = map(
lambda dep: _get_dep_path(dep, args.host_url, args.out_folder),
request_list)
deps = map(os.path.normpath, request_list)
with open(
os.path.join(_CWD, args.depfile), 'w', newline='', encoding='utf-8') as f:
f.write(out_file_path + ': ' + ' '.join(deps))
def _generate_rollup_config(out_dir, in_path, bundle_dir_path, host_url,
excludes, external_paths):
rollup_config_file = os.path.join(out_dir, 'rollup.config.mjs')
path_to_plugin = os.path.join(
os.path.relpath(_HERE_PATH, out_dir), 'rollup_plugin.mjs')
config_content = r'''
import plugin from '{plugin_path}';
export default ({{
plugins: [
plugin('{in_path}', '{bundle_dir_path}', '{host_url}', {exclude_list},
{external_path_list}) ]
}});
'''.format(
plugin_path=path_to_plugin.replace('\\', '/'),
in_path=in_path.replace('\\', '/'),
bundle_dir_path=bundle_dir_path.replace('\\', '/'),
host_url=host_url,
exclude_list=json.dumps(excludes),
external_path_list=json.dumps(external_paths))
with open(rollup_config_file, 'w', newline='', encoding='utf-8') as f:
f.write(config_content)
return rollup_config_file
def _generate_manifest_file(out_dir, bundled_paths, bundle_dir_path,
manifest_out_path):
manifest = {}
for bundled_path in bundled_paths:
sourcemap_file = bundled_path + '.map'
with open(sourcemap_file, 'r', encoding='utf-8') as f:
sourcemap = json.loads(f.read())
if not 'sources' in sourcemap:
raise Exception('rollup could not construct source map')
sources = sourcemap['sources']
replaced_sources = []
bundle_to_output = os.path.relpath(out_dir,
os.path.join(out_dir, bundle_dir_path))
for source in sources:
if bundle_to_output != ".":
replaced_sources.append(source.replace(bundle_to_output + "/", "", 1))
else:
replaced_sources.append(source)
filepath = os.path.join(bundle_dir_path,
os.path.basename(bundled_path)).replace(
'\\', '/')
manifest[filepath] = replaced_sources
with open(manifest_out_path, 'w', newline='', encoding='utf-8') as f:
f.write(json.dumps(manifest))
def _bundle(out_folder, in_path, manifest_out_path, js_module_in_files,
rollup_config_file):
bundle_dir_path = os.path.dirname(js_module_in_files[0])
out_dir = out_folder if not bundle_dir_path else os.path.join(
out_folder, bundle_dir_path)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
rollup_args = [os.path.join(in_path, f) for f in js_module_in_files]
bundled_paths = []
bundle_names = []
assert len(js_module_in_files) < 3, '3+ input files not supported'
for index, js_file in enumerate(js_module_in_files):
bundle_name = '%s.rollup.js' % js_file[:-len('.js')]
assert os.path.dirname(js_file) == bundle_dir_path, \
'All input files must be in the same directory.'
bundled_paths.append(os.path.join(out_folder, bundle_name))
bundle_names.append(bundle_name)
if (len(js_module_in_files) == 2):
shared_file_name = 'shared.rollup.js'
rollup_args += ['--chunkFileNames', shared_file_name]
bundled_paths.append(os.path.join(out_dir, shared_file_name))
bundle_names.append(os.path.join(bundle_dir_path, shared_file_name))
node.RunNode([node_modules.PathToRollup()] + rollup_args + [
'--format',
'esm',
'--dir',
out_dir,
'--entryFileNames',
'[name].rollup.js',
'--sourcemap',
'--sourcemapExcludeSources',
'--config',
rollup_config_file,
])
_generate_manifest_file(out_folder, bundled_paths, bundle_dir_path,
manifest_out_path)
for bundled_file in bundled_paths:
with open(bundled_file, 'r', encoding='utf-8') as f:
output = f.read()
assert "<if expr" not in output, \
'Unexpected <if expr> found in bundled output. Check that all ' + \
'input files using such expressions are preprocessed.'
return bundle_names
def _optimize(in_folder, args):
in_path = os.path.normpath(os.path.join(_CWD, in_folder)).replace('\\', '/')
out_path = os.path.join(_CWD, args.out_folder).replace('\\', '/')
manifest_out_path = _request_list_path(out_path, args.target_name)
excludes = [
'strings.m.js',
]
excludes.extend(args.exclude or [])
for exclude in excludes:
extension = os.path.splitext(exclude)[1]
assert extension == '.js', f'Unexpected |excludes| entry: {exclude}.' + \
' Only .js files can appear in |excludes|.'
external_paths = args.external_paths or []
if "chrome/browser/resources/extensions" in in_folder:
excludes = [e for e in excludes if "chrome:" not in e]
external_paths = [p for p in external_paths if "chrome:" not in p]
if args.rollup_config:
rollup_config_file = args.rollup_config
else:
bundle_dir_path = os.path.dirname(args.js_module_in_files[0])
rollup_config_file = _generate_rollup_config(out_path, in_path,
bundle_dir_path, args.host_url,
excludes, external_paths)
js_module_out_files = _bundle(out_path, in_path, manifest_out_path,
args.js_module_in_files, rollup_config_file)
return {
'manifest_out_path': manifest_out_path,
'js_module_out_files': js_module_out_files,
}
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument('--depfile', required=True)
parser.add_argument('--target_name', required=True)
parser.add_argument('--exclude', nargs='*')
parser.add_argument('--external_paths', nargs='*')
parser.add_argument('--host', required=True)
parser.add_argument('--input', required=True)
parser.add_argument('--out_folder', required=True)
parser.add_argument('--js_module_in_files', nargs='*', required=True)
parser.add_argument('--out-manifest')
parser.add_argument('--rollup_config')
args = parser.parse_args(argv)
args.depfile = os.path.normpath(args.depfile)
args.input = os.path.normpath(args.input)
args.out_folder = os.path.normpath(args.out_folder)
scheme_end_index = args.host.find('://')
if (scheme_end_index == -1):
args.host_url = 'arkweb://%s/' % args.host
else:
args.host_url = args.host
optimize_output = _optimize(args.input, args)
with open(optimize_output['manifest_out_path'], 'r', encoding='utf-8') as f:
manifest = json.loads(f.read())
if args.out_manifest:
manifest_data = {
'base_dir': args.out_folder.replace('\\', '/'),
'files': list(manifest.keys()),
}
with open(
os.path.normpath(os.path.join(_CWD, args.out_manifest)),
'w',
newline='',
encoding='utf-8') as manifest_file:
json.dump(manifest_data, manifest_file)
dep_file_header = os.path.join(args.out_folder,
optimize_output['js_module_out_files'][0])
_update_dep_file(args.input, args, dep_file_header, manifest)
if __name__ == '__main__':
main(sys.argv[1:])