def env_load_template(env, in_file): """ Load a single template into the environment, handling the appropriate errors. Returns the loaded template """ try: return env.get_template(in_file) except TemplateNotFound as e: raise ToolsException('template not found: %s' % str(e)) except TemplateSyntaxError as e: raise ToolsException('template syntax error: %s' % str(e))
def tzjs_compact(options, infile, outfile): LOG.info("compacting from %s to %s", infile, outfile) if options.yui is not None: command = ['java', '-jar', options.yui, '--line-break', str(options.length), '--type', 'js', '-o', outfile, infile] elif options.closure is not None: command = ['java', '-jar', options.closure, '--js_output_file=' + outfile, '--js=' + infile] elif options.uglifyjs is not None: # For nodejs on win32 we need posix style paths for the js # module, so convert to relative path uglify_rel_path = relpath(options.uglifyjs).replace('\\', '/') command = ['node', uglify_rel_path, '-o', outfile, infile] LOG.info(" CMD: %s" % command) subproc = SubProc(command) error_code = subproc.time_popen() if 0 != error_code: raise ToolsException("compactor command returned error code %d: %s " \ % (error_code, " ".join(command)))
def _find_in_dirs_or_error(name): file_path = find_file_in_dirs(name, options.templatedirs) if file_path is None: raise ToolsException("No file '%s' in any template dir" % name) if file_path in includes: LOG.info(" include '%s' (%s) already listed" % (name, file_path)) return LOG.info(" resolved '%s' to path '%s'" % (name, file_path)) includes.append(file_path)
def inject_js_from_options(options): """ Given the build options, find (if necessary), all includes that must be injected for canvas mode to work. This is done by searching for webgl_engine_file in any of the template directories, and collecting the list of all .js files that reside there. """ inject_list = [] if options.noinject: return inject_list mode = options.mode # Put debug.js at the top (if in debug mode), and ALWAYS include # vmath.js if mode in ['plugin-debug', 'canvas-debug', 'webworker-debug' ] or not options.stripdebug: inject_list.append('jslib/debug.js') inject_list.append('jslib/vmath.js') # Include webgl includes in canvas mode if mode in ['canvas', 'canvas-debug']: LOG.info("Looking for jslib/webgl ...") webgl_engine_file = 'jslib/webgl/turbulenzengine.js' webgl_engine_dir = os.path.dirname(webgl_engine_file) # Find absolute path of webgl_engine_file webgl_abs_path = None for t in options.templatedirs: p = os.path.join(t, webgl_engine_file) if os.path.exists(p): webgl_abs_path = os.path.dirname(p) LOG.info("Found at: %s", webgl_abs_path) break if webgl_abs_path is None: raise ToolsException("No '%s' in any template dir" \ % webgl_engine_file) webgl_abs_files = glob.glob(webgl_abs_path + "/*.js") inject_list += [ 'jslib/utilities.js', 'jslib/aabbtree.js', 'jslib/observer.js' ] inject_list += \ [ webgl_engine_dir + "/" + os.path.basename(f) for f in webgl_abs_files ] return inject_list
def output_dependency_info(dependency_file, output_file, dependencies): """ This dependency write outputs dependency information in a format consistent with the GCC -M flags. """ try: with open(dependency_file, "wb") as f: f.write(output_file) f.write(" ") f.write(dependency_file) f.write(" : \\\n") for d in dependencies: f.write(" ") f.write(d) f.write(" \\\n") f.write("\n\n") for d in dependencies: f.write(d) f.write(" :\n\n") except IOError: raise ToolsException("failed to write file: %s" % dependency_file)
def render_js(context, options, templates_js, inject_js): """ Renders the templates in templates_js, as if the first template began with include declarations for each of the files in inject_js. Returns the result of rendering, and the list of includes that were not inlined. (rendered_js, inc_js) For dev modes, the list of includes is returned in inc_js as relative paths from the output file. For release modes, includes are all inlined (inc_js == []). """ regex_use_strict = re_compile('"use strict";') out = [] inc_js = [] outfile_dir = os.path.abspath(os.path.dirname(options.output)) + os.sep includes_seen = [] # Any headers if options.use_strict: out.append('"use strict";') if options.mode in ['plugin', 'canvas']: out.append('(function () {') # Functions for handling includes def _find_include_or_error(name): try: f = find_file_in_dirs(name, options.templatedirs) except Exception, ex: raise ToolsException(str(ex)) if f is None: raise ToolsException("No file '%s' in any template dir" % name) LOG.info(" resolved '%s' to path '%s'" % (name, f)) return f
def context_from_options(options, title): # Sanity check if options.hybrid: if options.mode not in ['canvas', 'canvas-debug']: raise ToolsException( "--hybrid option available only in canvas and " "canvas_dev modes") # Set up the context context = {} context['tz_app_title_name_var'] = title context['tz_app_title_var'] = title context['tz_development'] = options.mode in [ 'plugin-debug', 'canvas-debug' ] context['tz_canvas'] = options.mode in ['canvas', 'canvas-debug'] context['tz_hybrid'] = options.hybrid return context
def html_dump_dependencies(env, options, input_js, input_html): """ Dump the dependencies of the html file being output """ # For html, dependencies are: # - dev: html template deps, top-level js files # - release: html template deps # - canvas_dev: html template deps, top-level js files # - canvas: html template deps outfile_name = options.dependency_file if outfile_name is None: LOG.error("No dependency output file specified") return 1 # Collect html dependencies (if there are html files available) if 1 == len(input_html): try: deps = find_dependencies(input_html[0], options.templatedirs, env, ['default']) except Exception, e: raise ToolsException("dependency error: %s" % str(e))
def tzjs_generate(env, options, input_js): # The set of files to be injected Profiler.start('find_inject_code') inject_js = inject_js_from_options(options) Profiler.stop('find_inject_code') if 0 < len(inject_js): LOG.info("Files to inject:") for i in inject_js: LOG.info(" - '%s'" % i) # Create a context and render the template Profiler.start('load_templates') context = context_from_options(options, input_js[0]) templates_js = env_load_templates(env, input_js) Profiler.stop('load_templates') Profiler.start('render_js') (rendered_js, inc_js) = render_js(context, options, templates_js, inject_js) Profiler.stop('render_js') if 0 != len(inc_js): raise ToolsException("internal error") # If required, remove all calls to 'debug.*' methods BEFORE # compacting if options.stripdebug: strip_path = "strip-debug" if options.stripdebugpath: strip_path = normpath(abspath(options.stripdebugpath)) LOG.info("Stripping debug method calls ...") # Check we can actually run strip debug, with the given path p = subprocess.Popen('%s -h' % strip_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) p.communicate() if p.returncode != 0: raise ToolsException( \ "\n\tstrip-debug tool could not be found, check it's on your path\n" "\tor supply the path with --strip-debug <path>. To run maketzjs\n" "\twithout stripping debug code run with --no-strip-debug." ) Profiler.start('strip_debug') strip_debug_flags = "-Ddebug=false" # Add the default flags first, in case the custom flags # override them. if options.verbose: strip_debug_flags += " -v" for s in options.stripnamespaces: strip_debug_flags += " --namespace %s" % s for v in options.stripvars: strip_debug_flags += " -D %s" % v if options.ignoreerrors: strip_debug_flags += " --ignore-errors" # Launch the strip command and pass in the full script via # streams. strip_cmd = "%s %s" % (strip_path, strip_debug_flags) LOG.info("Strip cmd: %s" % strip_cmd) p = subprocess.Popen(strip_cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stripped_js, err) = p.communicate(rendered_js) strip_retval = p.wait() if 0 != strip_retval: with NamedTemporaryFile(delete = False) as t: t.write(rendered_js) raise ToolsException( \ "strip-debug tool exited with code %d and stderr:\n\n%s\n" "The (merged) input probably contains a syntax error. It has " "been written to:\n %s\nfor inspection." \ % (strip_retval, err, t.name)) if not err is None and len(err) > 0: print "error output from strip-debug tool:" print "%s" % err rendered_js = stripped_js Profiler.stop('strip_debug') # If required, compact the JS via a temporary file, otherwise just # write out directly to the output file. if options.yui or options.closure or options.uglifyjs: Profiler.start('compact') with NamedTemporaryFile(delete = False) as t: LOG.info("Writing temp JS to '%s'" % t.name) t.write(rendered_js) LOG.info("Compacting temp JS to '%s'" % options.output) tzjs_compact(options, t.name, options.output) remove(t.name) Profiler.stop('compact') else: LOG.info("Writing JS to '%s'" % options.output) Profiler.start('write_out') try: with open(options.output, 'wb') as f: f.write(rendered_js) LOG.info("Succeeded") except IOError: raise ToolsException("failed to write file: %s" % options.output) Profiler.stop('write_out') return 0
def html_generate(env, options, input_js, input_html): """ Generate html based on the templates and build mode. """ # - dev, canvas_dev: # render top-level js files into a temporary file # collect the .js files that need to be included # setup includes, startup code and the js render result into variables # render html template # # - release, canvas: # need to know name of output js file # setup startup code to point to .tzjs or .js file # render html template # Load templates (using default html template if not specified) Profiler.start('load_templates') template_html = load_html_template(env, input_html) if template_html is None: LOG.error("failed to load file %s from template dirs", input_html[0]) exit(1) # Get context if len(input_js) > 0: title = input_js[0] elif options.codefile: title = options.codefile elif len(input_html) > 0: title = input_html[0] else: title = "Unknown" title = splitext(basename(title))[0] context = context_from_options(options, title) Profiler.stop('load_templates') Profiler.start('code_gen') # In development modes, render the JS code that needs embedding rendered_js = "" inc_js = [] if options.mode in ['plugin-debug', 'canvas-debug']: inject_js = inject_js_from_options(options) Profiler.start('load_js_templates') templates_js = env_load_templates(env, input_js) Profiler.stop('load_js_templates') (rendered_js, inc_js) = render_js(context, options, templates_js, inject_js) # Add the HTML and JS code into the tz_* variables default_add_code(options, context, rendered_js, inc_js) Profiler.stop('code_gen') Profiler.start('html_render') # Render the template and write it out try: res = template_html.render(context) except Exception, e: raise ToolsException("Error in '%s': %s %s" \ % (input_html, e.__class__.__name__, str(e)))
Profiler.stop('code_gen') Profiler.start('html_render') # Render the template and write it out try: res = template_html.render(context) except Exception, e: raise ToolsException("Error in '%s': %s %s" \ % (input_html, e.__class__.__name__, str(e))) try: with open(options.output, "wb") as f: f.write(res.encode('utf-8')) except IOError: raise ToolsException("failed to create file: %s" % options.output) Profiler.stop('html_render') return 0 ############################################################ def main(): (options, args, parser) = simple_options(_parser, __version__, __dependencies__, input_required=False)
def _find_include_or_error(name): try: f = find_file_in_dirs(name, options.templatedirs) except Exception, ex: raise ToolsException(str(ex))
def tzjs_generate(env, options, input_js): # The set of files to be injected Profiler.start('find_inject_code') inject_js = inject_js_from_options(options) Profiler.stop('find_inject_code') if 0 < len(inject_js): LOG.info("Files to inject:") for i in inject_js: LOG.info(" - '%s'", i) # Create a context and render the template Profiler.start('load_templates') context = context_from_options(options, input_js[0]) templates_js = env_load_templates(env, input_js) Profiler.stop('load_templates') Profiler.start('render_js') (rendered_js, inc_js) = render_js(context, options, templates_js, inject_js) rendered_js = rendered_js.encode('utf-8') Profiler.stop('render_js') if 0 != len(inc_js): raise ToolsException("internal error") # If required, remove all calls to 'debug.*' methods BEFORE # compacting # TODO: We write and read the files too many times. Better to # write once to a temporary, keep track of the name and invoke # each external command on files, creating subsequent temporaries # as required. if options.stripdebug: strip_path = "strip-debug" if options.stripdebugpath: strip_path = normpath(abspath(options.stripdebugpath)) LOG.info("Stripping debug method calls ...") # Check we can actually run strip debug, with the given path p = subprocess.Popen('%s -h' % strip_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) p.communicate() if p.returncode != 0: raise ToolsException( \ "\n\tstrip-debug tool could not be found, check it's on your path\n" "\tor supply the path with --strip-debug <path>. To run maketzjs\n" "\twithout stripping debug code run with --no-strip-debug." ) Profiler.start('strip_debug') strip_debug_flags = "-Ddebug=false" # Add the default flags first, in case the custom flags # override them. if options.verbose: strip_debug_flags += " -v" for s in options.stripnamespaces: strip_debug_flags += " --namespace %s" % s for v in options.stripvars: strip_debug_flags += " -D %s" % v if options.ignoreerrors: strip_debug_flags += " --ignore-errors" # Launch the strip command and pass in the full script via # streams. with NamedTemporaryFile(delete=False) as t: LOG.info("Writing temp JS to '%s'", t.name) t.write(rendered_js) with NamedTemporaryFile(delete=False) as tmp_out: pass strip_cmd = "%s %s -o %s %s" % (strip_path, strip_debug_flags, tmp_out.name, t.name) LOG.info("Strip cmd: %s", strip_cmd) strip_retval = subprocess.call(strip_cmd, shell=True) if 0 != strip_retval: raise ToolsException( \ "strip-debug tool exited with code %d\n" "The (merged) input probably contains a syntax error:\n" " %s" % (strip_retval, t.name)) rendered_js = read_file_utf8(tmp_out.name).encode('utf-8') remove(tmp_out.name) remove(t.name) Profiler.stop('strip_debug') # If required, compact the JS via a temporary file, otherwise just # write out directly to the output file. if options.mode != 'webworker-debug' and (options.yui or options.closure or options.uglifyjs): Profiler.start('compact') with NamedTemporaryFile(delete=False) as t: LOG.info("Writing temp JS to '%s'", t.name) t.write(rendered_js) LOG.info("Compacting temp JS to '%s'", options.output) tzjs_compact(options, t.name, options.output) remove(t.name) Profiler.stop('compact') else: LOG.info("Writing JS to '%s'", options.output) Profiler.start('write_out') try: with open(options.output, 'wb') as f: f.write(rendered_js) LOG.info("Succeeded") except IOError: raise ToolsException("failed to write file: %s" % options.output) Profiler.stop('write_out') return 0