| OLD | NEW |
| 1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python2 |
| 2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
| 3 | 3 |
| 4 # Copyright 2015 Google Inc. All Rights Reserved. | 4 # Copyright 2015 Google Inc. All Rights Reserved. |
| 5 # | 5 # |
| 6 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 # you may not use this file except in compliance with the License. | 7 # you may not use this file except in compliance with the License. |
| 8 # You may obtain a copy of the License at | 8 # You may obtain a copy of the License at |
| 9 # | 9 # |
| 10 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 62 |
| 63 # Name of the service worker static script. | 63 # Name of the service worker static script. |
| 64 SW_STATIC_SCRIPT_NAME = 'sw_static.js' | 64 SW_STATIC_SCRIPT_NAME = 'sw_static.js' |
| 65 | 65 |
| 66 # Largest number that the cache version can be. | 66 # Largest number that the cache version can be. |
| 67 MAX_CACHE_VERSION = 1000000 | 67 MAX_CACHE_VERSION = 1000000 |
| 68 | 68 |
| 69 # Where this file is located (so we can find resources). | 69 # Where this file is located (so we can find resources). |
| 70 SCRIPT_DIR = os.path.dirname(__file__) | 70 SCRIPT_DIR = os.path.dirname(__file__) |
| 71 | 71 |
| 72 # Name of the app info script. |
| 73 INFO_SCRIPT_NAME = 'app.info.js' |
| 74 |
| 72 # Maps dependency managers to the folder they install dependencies into. | 75 # Maps dependency managers to the folder they install dependencies into. |
| 73 DEPENDENCY_MANAGER_INSTALL_FOLDER = { | 76 DEPENDENCY_MANAGER_INSTALL_FOLDER = { |
| 74 'bower': 'bower_components', | 77 'bower': 'bower_components', |
| 75 'npm': 'node_modules', | 78 'npm': 'node_modules', |
| 76 } | 79 } |
| 77 | 80 |
| 78 SW_FORMAT_STRING = """/** | 81 SW_FORMAT_STRING = """/** |
| 79 * @file Service worker generated by Caterpillar. | 82 * @file Service worker generated by Caterpillar. |
| 80 */ | 83 */ |
| 81 | 84 |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 sw_js = generate_service_worker(output_dir, ca_manifest, required_js_paths, | 436 sw_js = generate_service_worker(output_dir, ca_manifest, required_js_paths, |
| 434 boilerplate_dir) | 437 boilerplate_dir) |
| 435 | 438 |
| 436 # We can now write the service worker. Note that it must be in the root. | 439 # We can now write the service worker. Note that it must be in the root. |
| 437 sw_path = os.path.join(output_dir, SW_SCRIPT_NAME) | 440 sw_path = os.path.join(output_dir, SW_SCRIPT_NAME) |
| 438 logging.debug('Writing service worker to `%s`.', sw_path) | 441 logging.debug('Writing service worker to `%s`.', sw_path) |
| 439 with open(sw_path, 'w') as sw_file: | 442 with open(sw_path, 'w') as sw_file: |
| 440 sw_file.write(surrogateescape.encode(sw_js)) | 443 sw_file.write(surrogateescape.encode(sw_js)) |
| 441 | 444 |
| 442 | 445 |
| 446 def add_app_info(output_dir, ca_manifest, config): |
| 447 """Adds an app info script, containing metadata, to a web app. |
| 448 |
| 449 Args: |
| 450 output_dir: Path to web app to add app info script to. |
| 451 ca_manifest: Chrome App manifest dictionary. |
| 452 config: Configuration dictionary. |
| 453 """ |
| 454 logging.debug('Generating app info script.') |
| 455 js_manifest = json.dumps( |
| 456 ca_manifest, sort_keys=True, indent=2).replace('"', "'") |
| 457 app_id = config['id'] |
| 458 app_info_js = ('chrome.caterpillar.manifest = {manifest};\n' |
| 459 'chrome.caterpillar.appId = \'{app_id}\';\n').format( |
| 460 manifest=js_manifest, |
| 461 app_id=app_id) |
| 462 app_info_path = os.path.join(output_dir, INFO_SCRIPT_NAME) |
| 463 logging.debug('Writing app info script to `%s`.', app_info_path) |
| 464 with open(app_info_path, 'w') as app_info_file: |
| 465 app_info_file.write(app_info_js.encode('utf-8')) |
| 466 |
| 467 |
| 443 class InstallationError(Exception): | 468 class InstallationError(Exception): |
| 444 """Exception raised when a dependency fails to install.""" | 469 """Exception raised when a dependency fails to install.""" |
| 445 | 470 |
| 446 pass | 471 pass |
| 447 | 472 |
| 448 | 473 |
| 449 def install_dependency(call, output_dir): | 474 def install_dependency(call, output_dir): |
| 450 """Installs a dependency into a directory. | 475 """Installs a dependency into a directory. |
| 451 | 476 |
| 452 Assumes that there is no output on stdout if installation fails. | 477 Assumes that there is no output on stdout if installation fails. |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 for dependency in dependencies: | 643 for dependency in dependencies: |
| 619 # Note that dependencies are installed into the root, but we need paths | 644 # Note that dependencies are installed into the root, but we need paths |
| 620 # relative to Caterpillar's boilerplate directory. | 645 # relative to Caterpillar's boilerplate directory. |
| 621 dependency_path = os.path.join('..', | 646 dependency_path = os.path.join('..', |
| 622 DEPENDENCY_MANAGER_INSTALL_FOLDER[dependency['manager']], | 647 DEPENDENCY_MANAGER_INSTALL_FOLDER[dependency['manager']], |
| 623 dependency['name'], dependency['path']) | 648 dependency['name'], dependency['path']) |
| 624 required_dependency_paths.append(dependency_path) | 649 required_dependency_paths.append(dependency_path) |
| 625 | 650 |
| 626 required_polyfill_paths = polyfill_paths(polyfillable) | 651 required_polyfill_paths = polyfill_paths(polyfillable) |
| 627 | 652 |
| 653 # Additionally, we may generate some files we want to use in HTML script tags, |
| 654 # but we don't want to install as a dependency or copy from a static JS file. |
| 655 required_generated_paths = [] |
| 656 |
| 628 # Read in and check the manifest file. | 657 # Read in and check the manifest file. |
| 629 try: | 658 try: |
| 630 ca_manifest = chrome_app.manifest.get(input_dir) | 659 ca_manifest = chrome_app.manifest.get(input_dir) |
| 631 chrome_app.manifest.localize(ca_manifest, input_dir) | 660 chrome_app.manifest.localize(ca_manifest, input_dir) |
| 632 chrome_app.manifest.verify(ca_manifest) | 661 chrome_app.manifest.verify(ca_manifest) |
| 633 except ValueError as e: | 662 except ValueError as e: |
| 634 logging.error(e.message) | 663 logging.error(e.message) |
| 635 return | 664 return |
| 636 | 665 |
| 637 # TODO(alger): Identify background scripts and determine start_url. | 666 # TODO(alger): Identify background scripts and determine start_url. |
| 638 start_url = config['start_url'] | 667 start_url = config['start_url'] |
| 639 logging.info('Got start URL from config file: `%s`', start_url) | 668 logging.info('Got start URL from config file: `%s`', start_url) |
| 640 | 669 |
| 641 # Generate a progressive web app manifest. | 670 # Generate a progressive web app manifest. |
| 642 pwa_manifest = generate_web_manifest(ca_manifest, start_url) | 671 pwa_manifest = generate_web_manifest(ca_manifest, start_url) |
| 643 pwa_manifest_path = os.path.join(output_dir, PWA_MANIFEST_FILENAME) | 672 pwa_manifest_path = os.path.join(output_dir, PWA_MANIFEST_FILENAME) |
| 644 with open(pwa_manifest_path, 'w') as pwa_manifest_file: | 673 with open(pwa_manifest_path, 'w') as pwa_manifest_file: |
| 645 json.dump(pwa_manifest, pwa_manifest_file, indent=4, sort_keys=True) | 674 json.dump(pwa_manifest, pwa_manifest_file, indent=4, sort_keys=True) |
| 646 logging.debug('Wrote `%s` to `%s`.', PWA_MANIFEST_FILENAME, pwa_manifest_path) | 675 logging.debug('Wrote `%s` to `%s`.', PWA_MANIFEST_FILENAME, pwa_manifest_path) |
| 647 | 676 |
| 677 # Generate and write an app info file so we can access Chrome App metadata |
| 678 # from polyfills and scripts. |
| 679 add_app_info(output_dir, ca_manifest, config) |
| 680 required_generated_paths.append(os.path.join('..', INFO_SCRIPT_NAME)) |
| 681 |
| 648 # Remove unnecessary files from the output web app. This must be done before | 682 # Remove unnecessary files from the output web app. This must be done before |
| 649 # the service worker is generated, or these files will be cached. | 683 # the service worker is generated, or these files will be cached. |
| 650 cleanup_output_dir(output_dir) | 684 cleanup_output_dir(output_dir) |
| 651 | 685 |
| 652 # Edit the HTML and JS code of the output web app. | 686 # Edit the HTML and JS code of the output web app. |
| 653 # This is adding TODOs, injecting tags, etc. - anything that involves editing | 687 # This is adding TODOs, injecting tags, etc. - anything that involves editing |
| 654 # user code directly. This must be done before the static code is copied | 688 # user code directly. This must be done before the static code is copied |
| 655 # across, or the polyfills will have TODOs added to them. | 689 # across, or the polyfills will have TODOs added to them. |
| 656 # Order is significant here - always, then dependencies, then polyfills. | 690 # Order is significant here - always, then dependencies, then polyfills. |
| 657 required_script_paths = (required_always_paths + required_dependency_paths | 691 required_script_paths = (required_always_paths + required_generated_paths + |
| 658 + required_polyfill_paths) | 692 required_dependency_paths + required_polyfill_paths) |
| 659 edit_code(output_dir, required_script_paths, ca_manifest, config) | 693 edit_code(output_dir, required_script_paths, ca_manifest, config) |
| 660 | 694 |
| 661 # We want the static SW file to be copied in too, so we add it here. | 695 # We want the static SW file to be copied in too, so we add it here. |
| 662 # We have to add it after edit_code or it would be included in the HTML, but | 696 # We have to add it after edit_code or it would be included in the HTML, but |
| 663 # this is service worker-only code, and shouldn't be included there. | 697 # this is service worker-only code, and shouldn't be included there. |
| 664 required_always_paths.append(SW_STATIC_SCRIPT_NAME) | 698 required_always_paths.append(SW_STATIC_SCRIPT_NAME) |
| 665 | 699 |
| 666 # Copy static code from Caterpillar into the output web app. | 700 # Copy static code from Caterpillar into the output web app. |
| 667 # This must be done before the service worker is generated, or these files | 701 # This must be done before the service worker is generated, or these files |
| 668 # will not be cached. | 702 # will not be cached. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 if args.mode == 'config': | 781 if args.mode == 'config': |
| 748 configuration.generate_and_save(args.output, args.interactive) | 782 configuration.generate_and_save(args.output, args.interactive) |
| 749 | 783 |
| 750 elif args.mode == 'convert': | 784 elif args.mode == 'convert': |
| 751 config = configuration.load(args.config) | 785 config = configuration.load(args.config) |
| 752 convert_app(args.input, args.output, config, args.force) | 786 convert_app(args.input, args.output, config, args.force) |
| 753 | 787 |
| 754 | 788 |
| 755 if __name__ == '__main__': | 789 if __name__ == '__main__': |
| 756 sys.exit(main()) | 790 sys.exit(main()) |
| OLD | NEW |