def insert_todos_into_file(js_path): """Inserts TODO comments in a JavaScript file. The TODO comments inserted should draw attention to places in the converted app that the developer will need to edit to finish converting their app. Args: js_path: Path to JavaScript file. """ with open(js_path) as in_js_file: # This search is very naïve and will only check line-by-line if there # are easily spotted Chrome Apps API function calls. out_js_lines = [] for line_no, line in enumerate(in_js_file): line = surrogateescape.decode(line) api_call = chrome_app.apis.api_member_used(line) if api_call is not None: # Construct a TODO comment. newline = '\r\n' if line.endswith('\r\n') else '\n' todo = '// TODO(Caterpillar): Check usage of {}.{}'.format( api_call, newline) logging.debug('Inserting TODO in `%s:%d`:\n\t%s', js_path, line_no, todo) out_js_lines.append(todo) out_js_lines.append(line) with open(js_path, 'w') as out_js_file: logging.debug('Writing modified file `%s`.', js_path) out_js = surrogateescape.encode(''.join(out_js_lines)) out_js_file.write(out_js)
def add_service_worker(output_dir, chrome_app_manifest, required_js_paths, boilerplate_dir): """Adds service worker scripts to a web app. Args: output_dir: Path to web app to add service worker scripts to. chrome_app_manifest: Chrome App manifest dictionary. required_js_paths: List of paths to required scripts, relative to the boilerplate directory. boilerplate_dir: Caterpillar script directory within web app. """ # We have to copy the other scripts before we generate the service worker # caching script, or else they won't be cached. boilerplate_path = os.path.join(output_dir, boilerplate_dir) copy_script(REGISTER_SCRIPT_NAME, boilerplate_path) copy_script(SW_STATIC_SCRIPT_NAME, boilerplate_path) sw_js = generate_service_worker(output_dir, chrome_app_manifest, required_js_paths, boilerplate_dir) # We can now write the service worker. Note that it must be in the root. sw_path = os.path.join(output_dir, SW_SCRIPT_NAME) logging.debug('Writing service worker to `%s`.', sw_path) with open(sw_path, 'w') as sw_file: sw_file.write(surrogateescape.encode(sw_js))
def edit_code(output_dir, required_js_paths, chrome_app_manifest, config): """Directly edits the code of the output web app. All editing of user code should be called from this function. Args: output_dir: Path to web app. required_js_paths: Paths of scripts to be included in the web app, relative to Caterpillar's boilerplate directory in the output web app. chrome_app_manifest: Manifest dictionary of the _Chrome App_. config: Configuration dictionary. """ logging.debug('Editing web app code.') # Walk the app for JS and HTML. # Insert TODOs into JS. # Inject script and meta tags into HTML. dirwalk = os.walk(output_dir) for (dirpath, _, filenames) in dirwalk: for filename in filenames: path = os.path.join(dirpath, filename) root_path = os.path.relpath(output_dir, dirpath) if filename.endswith('.js'): insert_todos_into_file(path) elif filename.endswith('.html'): logging.debug('Editing `%s`.', path) with open(path) as in_html_file: soup = bs4.BeautifulSoup( surrogateescape.decode(in_html_file.read()), 'html.parser') inject_script_tags( soup, required_js_paths, root_path, config['boilerplate_dir'], path) inject_misc_tags(soup, chrome_app_manifest, root_path, path) logging.debug('Writing edited and prettified `%s`.', path) with open(path, 'w') as out_html_file: out_html_file.write(surrogateescape.encode(soup.prettify()))
def insert_todos_into_file(js_path): """Inserts TODO comments in a JavaScript file. The TODO comments inserted should draw attention to places in the converted app that the developer will need to edit to finish converting their app. Args: js_path: Path to JavaScript file. """ with open(js_path) as in_js_file: # This search is very naïve and will only check line-by-line if there # are easily spotted Chrome Apps API function calls. out_js_lines = [] for line_no, line in enumerate(in_js_file): line = surrogateescape.decode(line) api_call = chrome_app.apis.api_member_used(line) if api_call is not None: # Construct a TODO comment. newline = '\r\n' if line.endswith('\r\n') else '\n' todo = '// TODO(Caterpillar): Check usage of {}.{}'.format(api_call, newline) logging.debug('Inserting TODO in `%s:%d`:\n\t%s', js_path, line_no, todo) out_js_lines.append(todo) out_js_lines.append(line) with open(js_path, 'w') as out_js_file: logging.debug('Writing modified file `%s`.', js_path) out_js = surrogateescape.encode(''.join(out_js_lines)) out_js_file.write(out_js)
def generate_and_write(report_dir, chrome_app_manifest, apis, status, warnings, web_path, boilerplate_dir): """Generates a conversion report and writes it to a directory. Args: report_dir: Directory to write report to. chrome_app_manifest: Manifest dictionary of input Chrome App. apis: Dictionary mapping Chrome Apps API name to polyfill manifest dictionaries. status: Status representing conversion status of the entire app. warnings: List of general warnings logged during conversion. web_path: Path to output progressive web app. """ report = generate(chrome_app_manifest, apis, status, warnings, web_path, boilerplate_dir) report_path = os.path.join(report_dir, 'report.html') with open(report_path, 'w') as report_file: logging.info('Writing conversion report to `%s`.', report_path) report_file.write(surrogateescape.encode(report)) copy_css(report_dir) install_bower_dependencies(['lato', 'inconsolata', 'code-prettify'], report_dir)
def test_surrogate_encode(self): s = u'latin-1: caf\udce9; utf-8: caf\xe9' bs = surrogateescape.encode(s) self.assertIsInstance(bs, bytes) self.assertEqual(bs, b'latin-1: caf\xe9; utf-8: caf\xc3\xa9')