def test_bundle_suprocess(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('output', 'error') # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy System.bundle(app_name, force=True) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) self.assertEqual(command, 'jspm bundle {0} {1}'.format(app_name, outfile)) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('foo')\nSystem.import('app/dummy');\n") self.assertEqual(process_mock.communicate.call_count, 1)
def test_ioerror_caught(self, mock): def ioerror(): raise IOError("Error") mock_Popen(mock, side_effect=ioerror) with self.assertRaises(BundleError): System.bundle("app/dummy", force=True)
def test_sourcemap_comment_large_file(self, mock_version, mock_subproc_popen): """ Same test as test_sourcemap_comment, except with a 'file' that's more than 100 bytes (to read multiple blocks). """ mock_version.return_value = Version('0.15.7') app_name = 'app/dummy' lorem = ''' Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ''' def side_effect(*args, **kwargs): content = 'alert(\'{}\')\n//# sourceMappingURL=dummy.js.map'.format(lorem) _bundle(app_name, content=content) return ('output', 'error') # mock Popen/communicate mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('{}')\nSystem.import('app/dummy.js');\n" "//# sourceMappingURL=dummy.js.map".format(lorem))
def test_jspm_016_log_error(self, mock_version, mock_subproc_popen): """ Test that bundles are generated with --log=err. JSPM > 0.16.0 has the --log option that surpresses levels of output. """ mock_version.return_value = Version('0.16.3') app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('', 'Something went wrong') # no stdout, no stderr -> success # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy with self.assertRaises(BundleError) as ctx: system = System() system.bundle(app_name) self.assertEqual(ctx.exception.args[0], "Could not bundle \'app/dummy\': \nSomething went wrong") self.assertEqual(mock_subproc_popen.call_count, 1) self.assertEqual(process_mock.communicate.call_count, 1)
def test_jspm_016_log_error(self, mock_version, mock_subproc_popen): """ Test that bundles are generated with --log=err. JSPM > 0.16.0 has the --log option that surpresses levels of output. """ mock_version.return_value = Version('0.16.3') app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('', 'Something went wrong' ) # no stdout, no stderr -> success # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy with self.assertRaises(BundleError) as ctx: system = System() system.bundle(app_name) self.assertEqual( ctx.exception.args[0], "Could not bundle \'app/dummy\': \nSomething went wrong") self.assertEqual(mock_subproc_popen.call_count, 1) self.assertEqual(process_mock.communicate.call_count, 1)
def test_sourcemap_comment_end_newline(self, mock_version, mock_subproc_popen): """ Asserts that the sourcemap comment is still at the end - with ending newline """ mock_version.return_value = Version('0.15.7') app_name = 'app/dummy' def side_effect(*args, **kwargs): content = 'alert(\'foo\')\n//# sourceMappingURL=dummy.js.map\n' _bundle(app_name, content=content) return ('output', 'error') # mock Popen/communicate mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) with open(outfile, 'r') as of: js = of.read() self.assertEqual( js, "alert('foo')\nSystem.import('app/dummy.js');\n" "//# sourceMappingURL=dummy.js.map")
def test_bundle_suprocess(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('output', 'error') # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) self.assertEqual(command, 'jspm bundle {0} {1}'.format(app_name, outfile)) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('foo')\nSystem.import('app/dummy.js');\n") self.assertEqual(process_mock.communicate.call_count, 1)
def test_oserror_caught(self, mock): def oserror(): raise OSError('Error') mock_Popen(mock, side_effect=oserror) with self.assertRaises(BundleError): System.bundle('app/dummy', force=True)
def test_ioerror_caught(self, mock): def ioerror(): raise IOError('Error') mock_Popen(mock, side_effect=ioerror) with self.assertRaises(BundleError): system = System() system.bundle('app/dummy')
def test_bundlesfx_suprocess(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen) # Bundle app/dummy System.bundle('app/dummy', sfx=True, force=True) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/app/dummy.js') self.assertEqual(command, 'jspm bundle-sfx app/dummy {0}'.format(outfile)) self.assertEqual(process_mock.communicate.call_count, 1)
def test_bundle_result(self): """ Test that bundling an app returns the correct relative path. """ path = System.bundle('app/dummy') expected_path = os.path.join(settings.SYSTEMJS_OUTPUT_DIR, 'app/dummy.js') self.assertEqual(path, expected_path)
def render(self, context): """ Build the filepath by appending the extension. """ module_path = self.path.resolve(context) if not settings.SYSTEMJS_ENABLED: if settings.SYSTEMJS_DEFAULT_JS_EXTENSIONS: name, ext = posixpath.splitext(module_path) if not ext: module_path = '{}.js'.format(module_path) tpl = """<script type="text/javascript">System.import('{app}');</script>""" return tpl.format(app=module_path) # else: create a bundle rel_path = System.get_bundle_path(module_path) url = staticfiles_storage.url(rel_path) tag_attrs = {'type': 'text/javascript'} for key, value in self.tag_attrs.items(): if not isinstance(value, bool): value = value.resolve(context) tag_attrs[key] = value return """<script{attrs} src="{url}"></script>""".format( url=url, attrs=flatatt(tag_attrs))
def test_bundle_result(self, mock_subproc_popen): """ Test that bundling an app returns the correct relative path. """ system = System() def side_effect(*args, **kwargs): _bundle('app/dummy') return ('output', 'error') # mock Popen/communicate mock_Popen(mock_subproc_popen, side_effect=side_effect) path = system.bundle('app/dummy') expected_path = os.path.join(settings.SYSTEMJS_OUTPUT_DIR, 'app/dummy.js') self.assertEqual(path, expected_path)
def handle(self, **options): self.verbosity = 2 self.storage = staticfiles_storage extensions = options.get('extensions') or ['html'] self.symlinks = options.get('symlinks') self.post_process = options['post_process'] # self.post_processed_files = [] self.extensions = handle_extensions(extensions) template_dirs = list(get_app_template_dirs('templates')) for config in settings.TEMPLATES: # only support vanilla Django templates if config['BACKEND'] != 'django.template.backends.django.DjangoTemplates': continue template_dirs += list(config['DIRS']) # find all template files all_files = [] for template_dir in template_dirs: for dirpath, dirnames, filenames in os.walk(template_dir, topdown=True, followlinks=self.symlinks): for filename in filenames: filepath = os.path.join(dirpath, filename) file_ext = os.path.splitext(filename)[1] if file_ext not in self.extensions: continue all_files.append(filepath) all_apps = [] for fp in all_files: with io.open(fp, 'r', encoding=settings.FILE_CHARSET) as template_file: src_data = template_file.read() for t in Lexer(src_data, None).tokenize(): if t.token_type == TOKEN_BLOCK: imatch = SYSTEMJS_TAG_RE.match(t.contents) if imatch: all_apps.append(imatch.group('app')) bundled_files = OrderedDict() storage = FileSystemStorage(settings.STATIC_ROOT, base_url=settings.STATIC_URL) for app in all_apps: rel_path = System.bundle(app, force=True) bundled_files[rel_path] = (storage, rel_path) if self.post_process and hasattr(self.storage, 'post_process'): processor = self.storage.post_process(bundled_files, dry_run=False) for original_path, processed_path, processed in processor: if isinstance(processed, Exception): # pragma: no cover self.stderr.write("Post-processing '%s' failed!" % original_path) # Add a blank line before the traceback, otherwise it's # too easy to miss the relevant part of the error message. self.stderr.write("") raise processed if processed: # pragma: no cover self.log("Post-processed '%s' as '%s'" % (original_path, processed_path), level=1) else: self.log("Skipped post-processing '%s'" % original_path) # pragma: no cover
def render(self, context): """ Build the filepath by appending the extension. """ module_path = self.path.resolve(context) if not settings.SYSTEMJS_ENABLED: if settings.SYSTEMJS_DEFAULT_JS_EXTENSIONS: name, ext = posixpath.splitext(module_path) if not ext: module_path = '{}.js'.format(module_path) if settings.SYSTEMJS_SERVER_URL: tpl = """<script src="{url}{app}" type="text/javascript"></script>""" else: tpl = """<script type="text/javascript">System.import('{app}');</script>""" return tpl.format(app=module_path, url=settings.SYSTEMJS_SERVER_URL) # else: create a bundle rel_path = System.get_bundle_path(module_path) url = staticfiles_storage.url(rel_path) tag_attrs = {'type': 'text/javascript'} for key, value in self.tag_attrs.items(): if not isinstance(value, bool): value = value.resolve(context) tag_attrs[key] = value return """<script{attrs} src="{url}"></script>""".format( url=url, attrs=flatatt(tag_attrs) )
def test_bundlesfx_suprocess(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen) # Bundle app/dummy system = System(sfx=True) system.bundle('app/dummy') self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/app/dummy.js') self.assertEqual(command, 'jspm bundle-sfx app/dummy {0}'.format(outfile)) self.assertEqual(process_mock.communicate.call_count, 1)
def test_jspm_version_suprocess(self, mock_subproc_popen): """ Test that JSPM version discovery works. """ # mock Popen/communicate return_value = (b'0.15.7\nRunning against global jspm install.\n', '') process_mock = mock_Popen(mock_subproc_popen, return_value=return_value) system = System() # Call version version = system.get_jspm_version({'jspm': 'jspm'}) self.assertEqual(mock_subproc_popen.call_count, 1) self.assertEqual(version, Version('0.15.7')) command = mock_subproc_popen.call_args[0][0] self.assertEqual(command, 'jspm --version') self.assertEqual(process_mock.communicate.call_count, 1)
def test_jspm_version_suprocess_error(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ # mock Popen/communicate return_value = (b'gibberish', 'a jspm error') process_mock = mock_Popen(mock_subproc_popen, return_value=return_value) system = System() # Call version with self.assertRaises(BundleError): system.get_jspm_version({'jspm': 'jspm'}) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] self.assertEqual(command, 'jspm --version') self.assertEqual(process_mock.communicate.call_count, 1)
def test_jspm_016_log(self, mock_version, mock_subproc_popen): """ Test that bundles are generated with --log=err. JSPM > 0.16.0 has the --log option that surpresses levels of output. """ mock_version.return_value = Version('0.16.3') app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('', '') # no stdout, no stderr -> success # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) self.assertEqual( command, mock.call('jspm bundle {0} {1} --log err'.format( app_name, outfile), stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True, cwd=None)) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('foo')\nSystem.import('app/dummy.js');\n") self.assertEqual(process_mock.communicate.call_count, 1)
def test_jspm_016_log(self, mock_version, mock_subproc_popen): """ Test that bundles are generated with --log=err. JSPM > 0.16.0 has the --log option that surpresses levels of output. """ mock_version.return_value = Version('0.16.3') app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('', '') # no stdout, no stderr -> success # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) self.assertEqual( command, mock.call( 'jspm bundle {0} {1} --log err'.format(app_name, outfile), stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True, cwd=None ) ) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('foo')\nSystem.import('app/dummy.js');\n") self.assertEqual(process_mock.communicate.call_count, 1)
def render(self, context): """ Build the filepath by appending the extension. """ module_path = self.path.resolve(context) if not settings.SYSTEMJS_ENABLED: tpl = """<script type="text/javascript">System.import('{app}');</script>""" return tpl.format(app=module_path) # else: create a bundle rel_path = System.bundle(module_path) url = staticfiles_storage.url(rel_path) return """<script type="text/javascript" src="{url}"></script>""".format(url=url)
def test_bundle_minify_suprocess(self, mock_subproc_popen): """ Test that bundling calls the correct subprocess command """ app_name = 'app/dummy' def side_effect(*args, **kwargs): _bundle(app_name) return ('output', 'error') # mock Popen/communicate process_mock = mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System(minify=True) system.bundle('app/dummy') self.assertEqual(mock_subproc_popen.call_count, 1) command = mock_subproc_popen.call_args[0][0] outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/app/dummy.js') self.assertEqual(command, 'jspm bundle app/dummy {0} --minify'.format(outfile)) self.assertEqual(process_mock.communicate.call_count, 1)
def test_sourcemap_comment_end_newline(self, mock_version, mock_subproc_popen): """ Asserts that the sourcemap comment is still at the end - with ending newline """ mock_version.return_value = Version('0.15.7') app_name = 'app/dummy' def side_effect(*args, **kwargs): content = 'alert(\'foo\')\n//# sourceMappingURL=dummy.js.map\n' _bundle(app_name, content=content) return ('output', 'error') # mock Popen/communicate mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) with open(outfile, 'r') as of: js = of.read() self.assertEqual(js, "alert('foo')\nSystem.import('app/dummy.js');\n" "//# sourceMappingURL=dummy.js.map")
def test_sourcemap_comment_large_file(self, mock_version, mock_subproc_popen): """ Same test as test_sourcemap_comment, except with a 'file' that's more than 100 bytes (to read multiple blocks). """ mock_version.return_value = Version('0.15.7') app_name = 'app/dummy' lorem = ''' Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ''' def side_effect(*args, **kwargs): content = 'alert(\'{}\')\n//# sourceMappingURL=dummy.js.map'.format( lorem) _bundle(app_name, content=content) return ('output', 'error') # mock Popen/communicate mock_Popen(mock_subproc_popen, side_effect=side_effect) # Bundle app/dummy system = System() system.bundle(app_name) outfile = os.path.join(settings.STATIC_ROOT, 'SYSTEMJS/{0}.js'.format(app_name)) with open(outfile, 'r') as of: js = of.read() self.assertEqual( js, "alert('{}')\nSystem.import('app/dummy.js');\n" "//# sourceMappingURL=dummy.js.map".format(lorem))
def handle(self, **options): super(Command, self).handle(**options) self.post_process = options['post_process'] self.minimal = options.get('minimal') self.verbosity = 2 self.storage = copy(staticfiles_storage) self.storage.systemjs_bundling = True # set flag to check later # initialize SystemJS specific objects to process the bundles tracer = SystemTracer(node_path=options.get('node_path')) system_opts = self.get_system_opts(options) system = System(**system_opts) has_different_options = self.minimal and tracer.get_bundle_options() != system_opts # discover the apps being imported in the templates all_apps = self.find_apps(templates=options.get('templates')) all_apps = set(sum(all_apps.values(), [])) bundled_files = OrderedDict() # FIXME: this should be configurable, if people use S3BotoStorage for example, it needs to end up there storage = FileSystemStorage(settings.STATIC_ROOT, base_url=settings.STATIC_URL) for app in all_apps: # do we need to generate the bundle for this app? if self.minimal and not (has_different_options or tracer.check_needs_update(app)): # check if the bundle actually exists - if it doesn't, don't skip it # this happens on the first ever bundle bundle_path = System.get_bundle_path(app) if self.storage.exists(bundle_path): self.stdout.write('Checked bundle for app \'{app}\', no changes found'.format(app=app)) continue rel_path = system.bundle(app) if not self.storage.exists(rel_path): self.stderr.write('Could not bundle {app}'.format(app=app)) else: self.stdout.write('Bundled {app} into {out}'.format(app=app, out=rel_path)) bundled_files[rel_path] = (storage, rel_path) if self.minimal and bundled_files: self.stdout.write('Generating the new depcache and writing to file...') all_deps = {app: tracer.trace(app) for app in all_apps} tracer.write_depcache(all_deps, system_opts) if self.post_process and hasattr(self.storage, 'post_process'): # post-process system.js if it's within settings.STATIC_ROOT systemjs_path = find_systemjs_location() try: within_static_root = self.storage.exists(systemjs_path) except SuspiciousFileOperation: within_static_root = False if within_static_root: relative = os.path.relpath(systemjs_path, settings.STATIC_ROOT) bundled_files[relative] = (storage, relative) processor = self.storage.post_process(bundled_files, dry_run=False) for original_path, processed_path, processed in processor: if isinstance(processed, Exception): # pragma: no cover self.stderr.write("Post-processing '%s' failed!" % original_path) # Add a blank line before the traceback, otherwise it's # too easy to miss the relevant part of the error message. self.stderr.write("") raise processed if processed: # pragma: no cover self.log("Post-processed '%s' as '%s'" % (original_path, processed_path), level=1) else: self.log("Skipped post-processing '%s'" % original_path) # pragma: no cover