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 |