예제 #1
0
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))
예제 #2
0
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)))
예제 #3
0
 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)
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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))
예제 #9
0
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
예제 #10
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)))
예제 #11
0
    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)
예제 #12
0
 def _find_include_or_error(name):
     try:
         f = find_file_in_dirs(name, options.templatedirs)
     except Exception, ex:
         raise ToolsException(str(ex))
예제 #13
0
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