"""Client Side Templating with `Google Closure Templates `_. Google Closure Templates is an external tool written in Java, which needs to be available. One way to get it is to install the `closure-soy `_ package:: pip install closure-soy No configuration is necessary in this case. You can also define a ``CLOSURE_TEMPLATES_PATH`` setting that points to the ``.jar`` file. Otherwise, an environment variable by the same name is tried. The filter will also look for a ``JAVA_HOME`` environment variable to run the ``.jar`` file, or will otherwise assume that ``java`` is on the system path. Supported configuration options: CLOSURE_EXTRA_ARGS A list of further options to be passed to the Closure compiler. There are a lot of them. For options which take values you want to use two items in the list:: ['--inputPrefix', 'prefix'] """ import subprocess import os import tempfile from webassets.exceptions import FilterError from webassets.filter.jst import JSTemplateFilter __all__ = ('ClosureTemplateFilter',) class ClosureTemplateFilter(JSTemplateFilter): name = 'closure_tmpl' options = { 'extra_args': 'CLOSURE_EXTRA_ARGS', } def process_templates(self, out, hunks, **kw): templates = [info['source_path'] for _, info in hunks] temp = tempfile.NamedTemporaryFile(dir='.', delete=True) args = ["--outputPathFormat", temp.name, '--srcs'] args.extend(templates) if self.extra_args: args.extend(self.extra_args) self.java_run(args) out.write(open(temp.name).read()) def setup(self): super(ClosureTemplateFilter, self).setup() try: self.jar = self.get_config('CLOSURE_TEMPLATES_PATH', what='Google Closure Soy Templates Compiler') except EnvironmentError: try: import closure_soy self.jar = closure_soy.get_jar_filename() except ImportError: raise EnvironmentError( "\nClosure Templates jar can't be found." "\nPlease either install the closure package:" "\n\n pip install closure-soy\n" "\nor provide a CLOSURE_TEMPLATES_PATH setting " "or an environment variable with the full path to " "the Closure compiler jar." ) self.java_setup() super(ClosureTemplateFilter, self).setup() def java_setup(self): # We can reasonably expect that java is just on the path, so # don't require it, but hope for the best. path = self.get_config(env='JAVA_HOME', require=False) if path is not None: self.java = os.path.join(path, 'bin/java') else: self.java = 'java' def java_run(self, args): proc = subprocess.Popen( [self.java, '-jar', self.jar] + args, # we cannot use the in/out streams directly, as they might be # StringIO objects (which are not supported by subprocess) stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=(os.name == 'nt')) stdout, stderr = proc.communicate() if proc.returncode: raise FilterError('%s: subprocess returned a ' 'non-success result code: %s, stdout=%s, stderr=%s' % ( self.name, proc.returncode, stdout, stderr))