Index: src/caterpillar.py |
diff --git a/src/caterpillar.py b/src/caterpillar.py |
index 134076fd17c53d239cb71f5de9ac18e031a98339..576bcd3a9cf0b9f1f6aa9365cc2cb7eca3e92cc9 100755 |
--- a/src/caterpillar.py |
+++ b/src/caterpillar.py |
@@ -69,6 +69,12 @@ MAX_CACHE_VERSION = 1000000 |
# Where this file is located (so we can find resources). |
SCRIPT_DIR = os.path.dirname(__file__) |
+# Maps dependency managers to the folder they install dependencies into. |
+DEPENDENCY_MANAGER_INSTALL_FOLDER = { |
+ 'bower': 'bower_components', |
+ 'npm': 'node_modules', |
+} |
+ |
SW_FORMAT_STRING = """/** |
* @file Service worker generated by Caterpillar. |
*/ |
@@ -347,15 +353,14 @@ def insert_todos_into_directory(output_dir): |
path = os.path.join(dirpath, filename) |
insert_todos_into_file(path) |
- |
-def generate_service_worker(output_dir, ca_manifest, polyfill_paths, |
+def generate_service_worker(output_dir, ca_manifest, required_js_paths, |
boilerplate_dir): |
"""Generates code for a service worker. |
Args: |
output_dir: Directory of the web app that this service worker will run in. |
ca_manifest: Chrome App manifest dictionary. |
- polyfill_paths: List of paths to required polyfill scripts, relative to the |
+ required_js_paths: List of paths to required scripts, relative to the |
boilerplate directory. |
boilerplate_dir: Caterpillar script directory within output web app. |
@@ -385,11 +390,11 @@ def generate_service_worker(output_dir, ca_manifest, polyfill_paths, |
# The polyfills we get as input are relative to the boilerplate directory, but |
# the service worker is in the root directory, so we need to change the paths. |
- polyfills_paths = [os.path.join(boilerplate_dir, path) |
- for path in polyfill_paths] |
+ required_js_paths = [os.path.join(boilerplate_dir, path) |
+ for path in required_js_paths] |
background_scripts = ca_manifest['app']['background'].get('scripts', []) |
- for script in polyfill_paths + background_scripts: |
+ for script in required_js_paths + background_scripts: |
logging.debug('Importing `%s` to the service worker.', script) |
sw_js += "importScripts('{}');\n".format(script) |
@@ -408,15 +413,14 @@ def copy_script(script, directory): |
logging.debug('Writing `%s` to `%s`.', path, new_path) |
shutil.copyfile(path, new_path) |
- |
-def add_service_worker(output_dir, ca_manifest, polyfill_paths, |
+def add_service_worker(output_dir, ca_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. |
ca_manifest: Chrome App manifest dictionary. |
- polyfill_paths: List of paths to required polyfill scripts, relative to the |
+ required_js_paths: List of paths to required scripts, relative to the |
boilerplate directory. |
boilerplate_dir: Caterpillar script directory within web app. |
""" |
@@ -426,7 +430,7 @@ def add_service_worker(output_dir, ca_manifest, polyfill_paths, |
copy_script(REGISTER_SCRIPT_NAME, boilerplate_path) |
copy_script(SW_STATIC_SCRIPT_NAME, boilerplate_path) |
- sw_js = generate_service_worker(output_dir, ca_manifest, polyfill_paths, |
+ sw_js = generate_service_worker(output_dir, ca_manifest, required_js_paths, |
boilerplate_dir) |
# We can now write the service worker. Note that it must be in the root. |
@@ -593,12 +597,33 @@ def convert_app(input_dir, output_dir, config, force=False): |
logging.warning('Could not polyfill Chrome APIs: %s', |
', '.join(not_polyfillable)) |
+ # Read in the polyfill manifests and store their dependencies. We can't |
+ # install them yet, though, since that has to be done after editing code or |
+ # the dependencies will also be edited. |
+ polyfill_manifests = polyfill_manifest.load_many(polyfillable) |
+ dependencies = [dependency |
+ for manifest in polyfill_manifests.values() |
+ for dependency in manifest['dependencies']] |
+ |
# List of paths of static code to be copied from Caterpillar into the output |
# web app, relative to Caterpillar's JS source directory. |
- required_js_paths = [ |
+ required_always_paths = [ |
'caterpillar.js', |
REGISTER_SCRIPT_NAME, |
- ] + polyfill_paths(polyfillable) |
+ ] |
+ |
+ # The dependencies and polyfills are also requirements, but we need to handle |
+ # them differently, so they're split up into two lists. |
+ required_dependency_paths = [] |
+ for dependency in dependencies: |
+ # Note that dependencies are installed into the root, but we need paths |
+ # relative to Caterpillar's boilerplate directory. |
+ dependency_path = os.path.join('..', |
+ DEPENDENCY_MANAGER_INSTALL_FOLDER[dependency['manager']], |
+ dependency['name'], dependency['path']) |
+ required_dependency_paths.append(dependency_path) |
+ |
+ required_polyfill_paths = polyfill_paths(polyfillable) |
# Read in and check the manifest file. |
try: |
@@ -628,26 +653,24 @@ def convert_app(input_dir, output_dir, config, force=False): |
# This is adding TODOs, injecting tags, etc. - anything that involves editing |
# user code directly. This must be done before the static code is copied |
# across, or the polyfills will have TODOs added to them. |
- edit_code(output_dir, required_js_paths, ca_manifest, config) |
+ # Order is significant here - always, then dependencies, then polyfills. |
+ required_script_paths = (required_always_paths + required_dependency_paths |
+ + required_polyfill_paths) |
+ edit_code(output_dir, required_script_paths, ca_manifest, config) |
# We want the static SW file to be copied in too, so we add it here. |
# We have to add it after edit_code or it would be included in the HTML, but |
# this is service worker-only code, and shouldn't be included there. |
- required_js_paths.append(SW_STATIC_SCRIPT_NAME) |
+ required_always_paths.append(SW_STATIC_SCRIPT_NAME) |
# Copy static code from Caterpillar into the output web app. |
# This must be done before the service worker is generated, or these files |
# will not be cached. |
- copy_static_code(required_js_paths, output_dir, boilerplate_dir) |
+ required_static_paths = required_always_paths + required_polyfill_paths |
+ copy_static_code(required_static_paths, output_dir, boilerplate_dir) |
- # Read in the polyfill manifests and install polyfill dependencies. |
- # This must be done after editing code (or the dependencies will also be |
- # edited) and before the service worker is generated (or the dependencies |
- # won't be cached). |
- polyfill_manifests = polyfill_manifest.load_many(polyfillable) |
- dependencies = [dependency |
- for manifest in polyfill_manifests.values() |
- for dependency in manifest['dependencies']] |
+ # Install the polyfill dependencies. This must be done before the service |
+ # worker is generated, or the dependencies won't be cached. |
try: |
install_dependencies(dependencies, output_dir) |
except ValueError as e: |
@@ -655,7 +678,8 @@ def convert_app(input_dir, output_dir, config, force=False): |
return |
# Generate and write a service worker. |
- add_service_worker(output_dir, ca_manifest, polyfill_paths(polyfillable), |
+ required_sw_paths = required_dependency_paths + required_polyfill_paths |
+ add_service_worker(output_dir, ca_manifest, required_sw_paths, |
boilerplate_dir) |
logging.info('Conversion complete.') |