summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/android/gyp/jinja_template.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/build/android/gyp/jinja_template.py')
-rwxr-xr-xthird_party/libwebrtc/build/android/gyp/jinja_template.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/android/gyp/jinja_template.py b/third_party/libwebrtc/build/android/gyp/jinja_template.py
new file mode 100755
index 0000000000..d42189ba38
--- /dev/null
+++ b/third_party/libwebrtc/build/android/gyp/jinja_template.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Renders one or more template files using the Jinja template engine."""
+
+import codecs
+import argparse
+import os
+import sys
+
+from util import build_utils
+from util import resource_utils
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from pylib.constants import host_paths
+
+# Import jinja2 from third_party/jinja2
+sys.path.append(os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'))
+import jinja2 # pylint: disable=F0401
+
+
+class _RecordingFileSystemLoader(jinja2.FileSystemLoader):
+ def __init__(self, searchpath):
+ jinja2.FileSystemLoader.__init__(self, searchpath)
+ self.loaded_templates = set()
+
+ def get_source(self, environment, template):
+ contents, filename, uptodate = jinja2.FileSystemLoader.get_source(
+ self, environment, template)
+ self.loaded_templates.add(os.path.relpath(filename))
+ return contents, filename, uptodate
+
+
+class JinjaProcessor(object):
+ """Allows easy rendering of jinja templates with input file tracking."""
+ def __init__(self, loader_base_dir, variables=None):
+ self.loader_base_dir = loader_base_dir
+ self.variables = variables or {}
+ self.loader = _RecordingFileSystemLoader(loader_base_dir)
+ self.env = jinja2.Environment(loader=self.loader)
+ self.env.undefined = jinja2.StrictUndefined
+ self.env.line_comment_prefix = '##'
+ self.env.trim_blocks = True
+ self.env.lstrip_blocks = True
+ self._template_cache = {} # Map of path -> Template
+
+ def Render(self, input_filename, variables=None):
+ input_rel_path = os.path.relpath(input_filename, self.loader_base_dir)
+ template = self._template_cache.get(input_rel_path)
+ if not template:
+ template = self.env.get_template(input_rel_path)
+ self._template_cache[input_rel_path] = template
+ return template.render(variables or self.variables)
+
+ def GetLoadedTemplates(self):
+ return list(self.loader.loaded_templates)
+
+
+def _ProcessFile(processor, input_filename, output_filename):
+ output = processor.Render(input_filename)
+
+ # If |output| is same with the file content, we skip update and
+ # ninja's restat will avoid rebuilding things that depend on it.
+ if os.path.isfile(output_filename):
+ with codecs.open(output_filename, 'r', 'utf-8') as f:
+ if f.read() == output:
+ return
+
+ with codecs.open(output_filename, 'w', 'utf-8') as output_file:
+ output_file.write(output)
+
+
+def _ProcessFiles(processor, input_filenames, inputs_base_dir, outputs_zip):
+ with build_utils.TempDir() as temp_dir:
+ path_info = resource_utils.ResourceInfoFile()
+ for input_filename in input_filenames:
+ relpath = os.path.relpath(os.path.abspath(input_filename),
+ os.path.abspath(inputs_base_dir))
+ if relpath.startswith(os.pardir):
+ raise Exception('input file %s is not contained in inputs base dir %s'
+ % (input_filename, inputs_base_dir))
+
+ output_filename = os.path.join(temp_dir, relpath)
+ parent_dir = os.path.dirname(output_filename)
+ build_utils.MakeDirectory(parent_dir)
+ _ProcessFile(processor, input_filename, output_filename)
+ path_info.AddMapping(relpath, input_filename)
+
+ path_info.Write(outputs_zip + '.info')
+ build_utils.ZipDir(outputs_zip, temp_dir)
+
+
+def _ParseVariables(variables_arg, error_func):
+ variables = {}
+ for v in build_utils.ParseGnList(variables_arg):
+ if '=' not in v:
+ error_func('--variables argument must contain "=": ' + v)
+ name, _, value = v.partition('=')
+ variables[name] = value
+ return variables
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--inputs', required=True,
+ help='GN-list of template files to process.')
+ parser.add_argument('--includes', default='',
+ help="GN-list of files that get {% include %}'ed.")
+ parser.add_argument('--output', help='The output file to generate. Valid '
+ 'only if there is a single input.')
+ parser.add_argument('--outputs-zip', help='A zip file for the processed '
+ 'templates. Required if there are multiple inputs.')
+ parser.add_argument('--inputs-base-dir', help='A common ancestor directory '
+ 'of the inputs. Each output\'s path in the output zip '
+ 'will match the relative path from INPUTS_BASE_DIR to '
+ 'the input. Required if --output-zip is given.')
+ parser.add_argument('--loader-base-dir', help='Base path used by the '
+ 'template loader. Must be a common ancestor directory of '
+ 'the inputs. Defaults to DIR_SOURCE_ROOT.',
+ default=host_paths.DIR_SOURCE_ROOT)
+ parser.add_argument('--variables', help='Variables to be made available in '
+ 'the template processing environment, as a GYP list '
+ '(e.g. --variables "channel=beta mstone=39")', default='')
+ parser.add_argument('--check-includes', action='store_true',
+ help='Enable inputs and includes checks.')
+ options = parser.parse_args()
+
+ inputs = build_utils.ParseGnList(options.inputs)
+ includes = build_utils.ParseGnList(options.includes)
+
+ if (options.output is None) == (options.outputs_zip is None):
+ parser.error('Exactly one of --output and --output-zip must be given')
+ if options.output and len(inputs) != 1:
+ parser.error('--output cannot be used with multiple inputs')
+ if options.outputs_zip and not options.inputs_base_dir:
+ parser.error('--inputs-base-dir must be given when --output-zip is used')
+
+ variables = _ParseVariables(options.variables, parser.error)
+ processor = JinjaProcessor(options.loader_base_dir, variables=variables)
+
+ if options.output:
+ _ProcessFile(processor, inputs[0], options.output)
+ else:
+ _ProcessFiles(processor, inputs, options.inputs_base_dir,
+ options.outputs_zip)
+
+ if options.check_includes:
+ all_inputs = set(processor.GetLoadedTemplates())
+ all_inputs.difference_update(inputs)
+ all_inputs.difference_update(includes)
+ if all_inputs:
+ raise Exception('Found files not listed via --includes:\n' +
+ '\n'.join(sorted(all_inputs)))
+
+
+if __name__ == '__main__':
+ main()