blob: 24b705713b48ca7058d5ca606357ec0cb8d605a4 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Copies file_manager/main.html to file_manager/test.html.
Modifies it to be able to run the CrOS FileManager app
as a regular web page in a single renderer.
"""
import argparse
import glob
import json
import os
import re
import shutil
import sys
import time
import xml.etree.ElementTree as ET
assert __name__ == '__main__'
parser = argparse.ArgumentParser()
parser.add_argument('--output')
args = parser.parse_args()
# If --output is not provided, write to local test.html.
output = args.output or os.path.abspath(
os.path.join(sys.path[0], '../../test.html'))
# SRC : Absolute path to //src/.
# GEN : Absolute path to $target_gen_dir.
# ROOT : Relative path from GEN to //src/ui/file_manager/file_manager.
# R_GEN : Directory where chrome://resources/ is copied to.
SRC = os.path.abspath(os.path.join(sys.path[0], '../../../../..')) + '/'
GEN = os.path.dirname(os.path.abspath(args.output)) + '/'
ROOT = os.path.relpath(SRC, GEN) + '/ui/file_manager/file_manager/'
R_GEN = 'test/gen/resources/'
scripts = []
GENERATED = 'Generated at %s by: %s' % (time.ctime(), sys.path[0])
GENERATED_HTML = '<!-- %s -->\n\n' % GENERATED
def read(path, mode='r'):
with open(os.path.join(SRC, path), mode) as f:
return f.read()
def write(path, content, mode='w'):
fullpath = os.path.join(GEN, path)
if not os.path.exists(os.path.dirname(fullpath)):
os.makedirs(os.path.dirname(fullpath))
with open(fullpath, mode) as f:
f.write(content)
def replaceline(f, match, lines):
"""Replace matching line in file with lines."""
for i in range(len(f)):
if match in f[i]:
return f[:i] + lines + f[i+1:]
return f
def includes2scripts(include_filename):
"""Convert <include src='foo'> to <script src='<prefix>foo'></script>."""
scripts.append('<!-- %s -->' % include_filename)
prefix = ROOT + include_filename[:include_filename.rindex('/')+1]
f = read('ui/file_manager/file_manager/' + include_filename).split('\n')
for i in range(len(f)):
l = f[i]
# Join back any include with a line-break.
if l == '// <include' and f[i+1].startswith('// src='):
f[i+1] = l + f[i+1][2:]
continue
if l.startswith('// <include '):
l = l.replace('// <include ', '<script ')
# main.js should be defer.
if 'src="main.js"' in l:
l = l.replace('src="main.js"', 'src="main.js" defer')
# Fix the path for scripts to be relative to ROOT.
if 'src="../../' in l:
l = l.replace('src="../../', 'src="' + ROOT)
else:
l = l.replace('src="', 'src="' + prefix)
tag = l + '</script>'
if tag not in scripts:
scripts.append(tag)
# Get strings from grdp files. Remove any ph/ex elements before getting text.
# Parse private_api_strings.cc to match the string name to the grdp message.
strings = {
'fontFamily': 'Roboto, sans-serif',
'fontSize': '75%',
'language': 'en',
'textDirection': 'ltr',
}
grdp_files = [
'chrome/app/chromeos_strings.grdp',
'ui/chromeos/file_manager_strings.grdp',
]
resource_bundle = {}
for grdp in grdp_files:
for msg in ET.fromstring(read(grdp)).iter('message'):
for ph in msg.findall('ph'):
for ex in ph.findall('ex'):
ph.remove(ex)
resource_bundle[msg.attrib['name']] = ''.join(msg.itertext()).strip()
private_api_strings = read('chrome/browser/chromeos/'
'file_manager/file_manager_string_util.cc')
for m in re.finditer(
r'SET_STRING\(\s*\"(.*?)\",\s+(\w+)\);', private_api_strings):
strings[m.group(1)] = resource_bundle.get(m.group(2), m.group(2))
# Substitute $i18n{} and $i18nRaw{} in template with strings from grdp files.
def i18n(template):
repl = lambda x: strings.get(x.group(1), x.group())
return re.sub(r'\$i18n(?:Raw)?\{(.*?)\}', repl, template)
# Copy from src_dir to R_GEN/dst_dir with substitutions.
def copyresources(src_dir, dst_dir):
for root, _, files in os.walk(SRC + src_dir):
for f in files:
srcf = os.path.join(root[len(SRC):], f)
dstf = R_GEN + dst_dir + srcf[len(src_dir):]
relpath = os.path.relpath(R_GEN, os.path.dirname(dstf)) + '/'
try:
write(dstf, i18n(read(srcf).replace('chrome://resources/', relpath)))
except UnicodeDecodeError:
# Binary files get utf-8 codec errors in py3, copy them as binary.
write(dstf, read(srcf, 'rb'), 'wb')
# Copy any files required in chrome://resources/... into test/gen/resources.
copyresources('ui/webui/resources/', '')
copyresources('third_party/polymer/v1_0/components-chromium/', 'polymer/v1_0/')
shutil.rmtree(GEN + R_GEN + 'polymer/v1_0/polymer', ignore_errors=True)
os.rename(GEN + R_GEN + 'polymer/v1_0/polymer2',
GEN + R_GEN + 'polymer/v1_0/polymer')
for css in glob.glob(GEN + '../../webui/resources/css/*.css'):
shutil.copy(css, GEN + R_GEN + 'css/')
colors = 'chromeos/colors/cros_colors.generated.css'
write(GEN + R_GEN + colors, open(GEN + '../../' + colors).read())
# Substitute $i18n{}.
# Update relative paths, and paths to chrome://resources/.
main_html = (i18n(read('ui/file_manager/file_manager/main.html'))
.replace('href="', 'href="' + ROOT)
.replace('src="', 'src="' + ROOT)
.replace(ROOT + 'chrome://resources/', R_GEN)
.split('\n'))
# Add scripts required for testing, and the test files (test/*.js).
src = [
'test/js/chrome_api_test_impl.js',
'../../webui/resources/js/assert.js',
'../../webui/resources/js/cr.js',
'../../webui/resources/js/cr/event_target.js',
'../../webui/resources/js/cr/ui/array_data_model.js',
'../../webui/resources/js/load_time_data.js',
'../../webui/resources/js/webui_resource_test.js',
'test/js/strings.js',
'common/js/files_app_entry_types.js',
'common/js/util.js',
'common/js/mock_entry.js',
'../base/js/volume_manager_types.js',
'background/js/volume_info_impl.js',
'background/js/volume_info_list_impl.js',
'background/js/volume_manager_impl.js',
'background/js/mock_volume_manager.js',
'foreground/js/constants.js',
'test/js/chrome_file_manager_private_test_impl.js',
'test/js/test_util.js',
]
src += ['test/' + s for s in os.listdir(
SRC + 'ui/file_manager/file_manager/test') if s.endswith('.js')]
scripts.append('<!-- required for testing -->')
scripts += ['<script src="%s%s"></script>' % (ROOT, s) for s in src]
# Convert all includes from:
# * foreground/js/main_scripts.js
# * background/js/background_common_scripts.js
# * background/js/background_scripts.js
# into <script> tags in main.html.
# Add polymer libs at start.
# Define FILE_MANAGER_ROOT which is required to locate test data files.
includes2scripts('foreground/js/main_scripts.js')
includes2scripts('background/js/background_common_scripts.js')
includes2scripts('background/js/background_scripts.js')
# test_util_base.js in background_common_scripts.js loads this at runtime.
# However, test/js/test_util.js copies some functions from it into its own
# test context, so provide it here.
scripts += ['<script src="%s%s"></script>' %
(ROOT, 'background/js/runtime_loaded_test_util.js')]
main_html = replaceline(main_html, 'foreground/js/main_scripts.js', [
"<script>var FILE_MANAGER_ROOT = '%s';</script>" % ROOT,
] + scripts)
def elements_path(elements_filename):
return '../../../../%sforeground/elements/%s' % (ROOT, elements_filename)
# Generate strings.js
# Copy all html files in foreground/elements and fix references to polymer
# Load QuickView in iframe rather than webview.
for filename, substitutions in (
('test/js/strings.js', (
('$GRDP', json.dumps(strings, sort_keys=True, indent=2)),
)),
('foreground/elements/elements_bundle.html', ()),
('foreground/js/elements_importer.js', (
("= 'foreground", "= 'test/gen/foreground"),
)),
('foreground/elements/files_password_dialog.html', ()),
('foreground/elements/files_format_dialog.html', ()),
('foreground/elements/files_icon_button.html', ()),
('foreground/elements/files_message.html', ()),
('foreground/elements/files_metadata_box.html', ()),
('foreground/elements/files_metadata_entry.html', ()),
('foreground/elements/files_quick_view.html', (
('="files_quick', '="' + elements_path('files_quick')),
('webview', 'iframe'),
)),
('foreground/elements/files_ripple.html', ()),
('foreground/elements/files_safe_media.html', (
('webview', 'iframe'),
('src="../../../../%sforeground/elements/' % ROOT, 'src="'),
)),
('foreground/elements/files_safe_media.js', (
("'foreground/elements", "'%sforeground/elements" % ROOT),
("'webview'", "'iframe'"),
("'contentload'", "'load'"),
('this.webview_.contentWindow.postMessage(data, FILES_APP_ORIGIN);',
('this.webview_.contentWindow.content.type = this.type;'
'this.webview_.contentWindow.content.src = this.src;')),
)),
('foreground/elements/files_spinner.html', ()),
('foreground/elements/files_toast.html', ()),
('foreground/elements/files_toggle_ripple.html', ()),
('foreground/elements/files_tooltip.html', ()),
('foreground/elements/files_xf_elements.html', (
('src="xf_',
'src="%sui/file_manager/file_manager/foreground/elements/xf_' % SRC),
)),
('foreground/elements/icons.html', ()),
):
buf = i18n(read('ui/file_manager/file_manager/' + filename))
buf = buf.replace('chrome://resources/', '../../resources/')
buf = buf.replace('src="files_', 'src="' + elements_path('files_'))
for old, new in substitutions:
buf = buf.replace(old, new)
write('test/gen/' + filename, buf)
main_html = replaceline(main_html, filename,
['<script src="test/gen/%s"></script>' % filename])
test_html = (GENERATED_HTML + '\n'.join(main_html)).encode('utf-8')
write('test.html', test_html, 'wb')