summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/util/generate_wrapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/build/util/generate_wrapper.py')
-rwxr-xr-xthird_party/libwebrtc/build/util/generate_wrapper.py217
1 files changed, 217 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/util/generate_wrapper.py b/third_party/libwebrtc/build/util/generate_wrapper.py
new file mode 100755
index 0000000000..07167e8655
--- /dev/null
+++ b/third_party/libwebrtc/build/util/generate_wrapper.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env vpython
+# Copyright 2019 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.
+
+"""Wraps an executable and any provided arguments into an executable script."""
+
+import argparse
+import os
+import sys
+import textwrap
+
+
+# The bash template passes the python script into vpython via stdin.
+# The interpreter doesn't know about the script, so we have bash
+# inject the script location.
+BASH_TEMPLATE = textwrap.dedent("""\
+ #!/usr/bin/env {vpython}
+ _SCRIPT_LOCATION = __file__
+ {script}
+ """)
+
+
+# The batch template reruns the batch script with vpython, with the -x
+# flag instructing the interpreter to ignore the first line. The interpreter
+# knows about the (batch) script in this case, so it can get the file location
+# directly.
+BATCH_TEMPLATE = textwrap.dedent("""\
+ @SETLOCAL ENABLEDELAYEDEXPANSION \
+ & {vpython}.bat -x "%~f0" %* \
+ & EXIT /B !ERRORLEVEL!
+ _SCRIPT_LOCATION = __file__
+ {script}
+ """)
+
+
+SCRIPT_TEMPLATES = {
+ 'bash': BASH_TEMPLATE,
+ 'batch': BATCH_TEMPLATE,
+}
+
+
+PY_TEMPLATE = textwrap.dedent("""\
+ import os
+ import re
+ import subprocess
+ import sys
+
+ _WRAPPED_PATH_RE = re.compile(r'@WrappedPath\(([^)]+)\)')
+ _PATH_TO_OUTPUT_DIR = '{path_to_output_dir}'
+ _SCRIPT_DIR = os.path.dirname(os.path.realpath(_SCRIPT_LOCATION))
+
+
+ def ExpandWrappedPath(arg):
+ m = _WRAPPED_PATH_RE.match(arg)
+ if m:
+ relpath = os.path.join(
+ os.path.relpath(_SCRIPT_DIR), _PATH_TO_OUTPUT_DIR, m.group(1))
+ npath = os.path.normpath(relpath)
+ if os.path.sep not in npath:
+ # If the original path points to something in the current directory,
+ # returning the normalized version of it can be a problem.
+ # normpath() strips off the './' part of the path
+ # ('./foo' becomes 'foo'), which can be a problem if the result
+ # is passed to something like os.execvp(); in that case
+ # osexecvp() will search $PATH for the executable, rather than
+ # just execing the arg directly, and if '.' isn't in $PATH, this
+ # results in an error.
+ #
+ # So, we need to explicitly return './foo' (or '.\\foo' on windows)
+ # instead of 'foo'.
+ #
+ # Hopefully there are no cases where this causes a problem; if
+ # there are, we will either need to change the interface to
+ # WrappedPath() somehow to distinguish between the two, or
+ # somehow ensure that the wrapped executable doesn't hit cases
+ # like this.
+ return '.' + os.path.sep + npath
+ return npath
+ return arg
+
+
+ def ExpandWrappedPaths(args):
+ for i, arg in enumerate(args):
+ args[i] = ExpandWrappedPath(arg)
+ return args
+
+
+ def FindIsolatedOutdir(raw_args):
+ outdir = None
+ i = 0
+ remaining_args = []
+ while i < len(raw_args):
+ if raw_args[i] == '--isolated-outdir' and i < len(raw_args)-1:
+ outdir = raw_args[i+1]
+ i += 2
+ elif raw_args[i].startswith('--isolated-outdir='):
+ outdir = raw_args[i][len('--isolated-outdir='):]
+ i += 1
+ else:
+ remaining_args.append(raw_args[i])
+ i += 1
+ if not outdir and 'ISOLATED_OUTDIR' in os.environ:
+ outdir = os.environ['ISOLATED_OUTDIR']
+ return outdir, remaining_args
+
+
+ def FilterIsolatedOutdirBasedArgs(outdir, args):
+ rargs = []
+ i = 0
+ while i < len(args):
+ if 'ISOLATED_OUTDIR' in args[i]:
+ if outdir:
+ # Rewrite the arg.
+ rargs.append(args[i].replace('${{ISOLATED_OUTDIR}}',
+ outdir).replace(
+ '$ISOLATED_OUTDIR', outdir))
+ i += 1
+ else:
+ # Simply drop the arg.
+ i += 1
+ elif (not outdir and
+ args[i].startswith('-') and
+ '=' not in args[i] and
+ i < len(args) - 1 and
+ 'ISOLATED_OUTDIR' in args[i+1]):
+ # Parsing this case is ambiguous; if we're given
+ # `--foo $ISOLATED_OUTDIR` we can't tell if $ISOLATED_OUTDIR
+ # is meant to be the value of foo, or if foo takes no argument
+ # and $ISOLATED_OUTDIR is the first positional arg.
+ #
+ # We assume the former will be much more common, and so we
+ # need to drop --foo and $ISOLATED_OUTDIR.
+ i += 2
+ else:
+ rargs.append(args[i])
+ i += 1
+ return rargs
+
+
+ def main(raw_args):
+ executable_path = ExpandWrappedPath('{executable_path}')
+ outdir, remaining_args = FindIsolatedOutdir(raw_args)
+ args = {executable_args}
+ args = FilterIsolatedOutdirBasedArgs(outdir, args)
+ executable_args = ExpandWrappedPaths(args)
+ cmd = [executable_path] + args + remaining_args
+ if executable_path.endswith('.py'):
+ cmd = [sys.executable] + cmd
+ return subprocess.call(cmd)
+
+
+ if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
+ """)
+
+
+def Wrap(args):
+ """Writes a wrapped script according to the provided arguments.
+
+ Arguments:
+ args: an argparse.Namespace object containing command-line arguments
+ as parsed by a parser returned by CreateArgumentParser.
+ """
+ path_to_output_dir = os.path.relpath(
+ args.output_directory,
+ os.path.dirname(args.wrapper_script))
+
+ with open(args.wrapper_script, 'w') as wrapper_script:
+ py_contents = PY_TEMPLATE.format(
+ path_to_output_dir=path_to_output_dir,
+ executable_path=str(args.executable),
+ executable_args=str(args.executable_args))
+ template = SCRIPT_TEMPLATES[args.script_language]
+ wrapper_script.write(
+ template.format(script=py_contents, vpython=args.vpython))
+ os.chmod(args.wrapper_script, 0o750)
+
+ return 0
+
+
+def CreateArgumentParser():
+ """Creates an argparse.ArgumentParser instance."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--executable',
+ help='Executable to wrap.')
+ parser.add_argument(
+ '--wrapper-script',
+ help='Path to which the wrapper script will be written.')
+ parser.add_argument(
+ '--output-directory',
+ help='Path to the output directory.')
+ parser.add_argument(
+ '--script-language',
+ choices=SCRIPT_TEMPLATES.keys(),
+ help='Language in which the wrapper script will be written.')
+ parser.add_argument('--use-vpython3',
+ dest='vpython',
+ action='store_const',
+ const='vpython3',
+ default='vpython',
+ help='Use vpython3 instead of vpython')
+ parser.add_argument(
+ 'executable_args', nargs='*',
+ help='Arguments to wrap into the executable.')
+ return parser
+
+
+def main(raw_args):
+ parser = CreateArgumentParser()
+ args = parser.parse_args(raw_args)
+ return Wrap(args)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))