summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/apple
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/build/apple')
-rw-r--r--third_party/libwebrtc/build/apple/OWNERS4
-rw-r--r--third_party/libwebrtc/build/apple/README.md12
-rw-r--r--third_party/libwebrtc/build/apple/apple_info_plist.gni60
-rw-r--r--third_party/libwebrtc/build/apple/compile_entitlements.gni51
-rw-r--r--third_party/libwebrtc/build/apple/compile_plist.gni76
-rw-r--r--third_party/libwebrtc/build/apple/convert_plist.gni41
-rw-r--r--third_party/libwebrtc/build/apple/plist_util.py265
-rw-r--r--third_party/libwebrtc/build/apple/tweak_info_plist.gni86
-rwxr-xr-xthird_party/libwebrtc/build/apple/tweak_info_plist.py447
-rw-r--r--third_party/libwebrtc/build/apple/write_pkg_info.py54
-rwxr-xr-xthird_party/libwebrtc/build/apple/xcrun.py52
11 files changed, 1148 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/apple/OWNERS b/third_party/libwebrtc/build/apple/OWNERS
new file mode 100644
index 0000000000..07d900ebed
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/OWNERS
@@ -0,0 +1,4 @@
+mark@chromium.org
+rohitrao@chromium.org
+rsesek@chromium.org
+sdefresne@chromium.org
diff --git a/third_party/libwebrtc/build/apple/README.md b/third_party/libwebrtc/build/apple/README.md
new file mode 100644
index 0000000000..f60185dc97
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/README.md
@@ -0,0 +1,12 @@
+# About
+
+`//build/apple` contains:
+ * GN templates and configurations shared by Apple platforms
+ * Python build scripts shared by Apple platforms
+
+This directory should only contain templates, configurations and scripts
+that are used exclusively on Apple platforms (currently iOS and macOS).
+They must also be independent of the specific platform.
+
+If a template, configuration or script is limited to only iOS or macOS,
+then they should instead be located in `//build/ios` or `//build/mac`.
diff --git a/third_party/libwebrtc/build/apple/apple_info_plist.gni b/third_party/libwebrtc/build/apple/apple_info_plist.gni
new file mode 100644
index 0000000000..fe51773dd0
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/apple_info_plist.gni
@@ -0,0 +1,60 @@
+# Copyright 2021 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.
+
+import("//build/apple/compile_plist.gni")
+
+# The base template used to generate Info.plist files for iOS and Mac apps and
+# frameworks.
+#
+# Arguments
+#
+# plist_templates:
+# string array, paths to plist files which will be used for the bundle.
+#
+# executable_name:
+# string, name of the generated target used for the product
+# and executable name as specified in the output Info.plist.
+#
+# format:
+# string, the format to `plutil -convert` the plist to when
+# generating the output.
+#
+# extra_substitutions:
+# (optional) string array, 'key=value' pairs for extra fields which are
+# specified in a source Info.plist template.
+#
+# output_name:
+# (optional) string, name of the generated plist file, default to
+# "$target_gen_dir/$target_name.plist".
+template("apple_info_plist") {
+ assert(defined(invoker.executable_name),
+ "The executable_name must be specified for $target_name")
+ executable_name = invoker.executable_name
+
+ compile_plist(target_name) {
+ forward_variables_from(invoker,
+ [
+ "plist_templates",
+ "testonly",
+ "deps",
+ "visibility",
+ "format",
+ ])
+
+ if (defined(invoker.output_name)) {
+ output_name = invoker.output_name
+ } else {
+ output_name = "$target_gen_dir/$target_name.plist"
+ }
+
+ substitutions = [
+ "EXECUTABLE_NAME=$executable_name",
+ "GCC_VERSION=com.apple.compilers.llvm.clang.1_0",
+ "PRODUCT_NAME=$executable_name",
+ ]
+ if (defined(invoker.extra_substitutions)) {
+ substitutions += invoker.extra_substitutions
+ }
+ }
+}
diff --git a/third_party/libwebrtc/build/apple/compile_entitlements.gni b/third_party/libwebrtc/build/apple/compile_entitlements.gni
new file mode 100644
index 0000000000..006d5ac2d5
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/compile_entitlements.gni
@@ -0,0 +1,51 @@
+# Copyright 2021 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.
+
+import("//build/apple/compile_plist.gni")
+
+# Template to merge multiple .entitlements files performing variable
+# substitutions.
+#
+# Arguments
+#
+# entitlements_templates:
+# string array, paths to entitlements files which will be used for the
+# bundle.
+#
+# substitutions:
+# string array, 'key=value' pairs used to replace ${key} by value
+# when generating the output plist file.
+#
+# output_name:
+# string, name of the generated entitlements file.
+template("compile_entitlements") {
+ assert(defined(invoker.entitlements_templates),
+ "A list of template plist files must be specified for $target_name")
+
+ compile_plist(target_name) {
+ forward_variables_from(invoker,
+ "*",
+ [
+ "entitlements_templates",
+ "format",
+ "plist_templates",
+ ])
+
+ plist_templates = invoker.entitlements_templates
+
+ # Entitlements files are always encoded in xml1.
+ format = "xml1"
+
+ # Entitlements files use unsubstitued variables, so define substitutions
+ # to leave those variables untouched.
+ if (!defined(substitutions)) {
+ substitutions = []
+ }
+
+ substitutions += [
+ "AppIdentifierPrefix=\$(AppIdentifierPrefix)",
+ "CFBundleIdentifier=\$(CFBundleIdentifier)",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/build/apple/compile_plist.gni b/third_party/libwebrtc/build/apple/compile_plist.gni
new file mode 100644
index 0000000000..90485b6a2a
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/compile_plist.gni
@@ -0,0 +1,76 @@
+# Copyright 2021 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.
+
+# Template to merge multiple plist files and perform variable substitutions.
+#
+# Arguments
+#
+# plist_templates:
+# string array, paths to plist files which will be used for the bundle.
+#
+# format:
+# string, the format to `plutil -convert` the plist to when
+# generating the output.
+#
+# substitutions:
+# string array, 'key=value' pairs used to replace ${key} by value
+# when generating the output plist file.
+#
+# output_name:
+# string, name of the generated plist file.
+template("compile_plist") {
+ assert(defined(invoker.plist_templates),
+ "A list of template plist files must be specified for $target_name")
+ assert(defined(invoker.format),
+ "The plist format must be specified for $target_name")
+ assert(defined(invoker.substitutions),
+ "A list of key=value pairs must be specified for $target_name")
+ assert(defined(invoker.output_name),
+ "The name of the output file must be specified for $target_name")
+
+ _output_name = invoker.output_name
+ _merged_name = get_path_info(_output_name, "dir") + "/" +
+ get_path_info(_output_name, "name") + "_merged." +
+ get_path_info(_output_name, "extension")
+
+ _merge_target = target_name + "_merge"
+
+ action(_merge_target) {
+ forward_variables_from(invoker,
+ [
+ "deps",
+ "testonly",
+ ])
+
+ script = "//build/apple/plist_util.py"
+ sources = invoker.plist_templates
+ outputs = [ _merged_name ]
+ args = [
+ "merge",
+ "-f=" + invoker.format,
+ "-o=" + rebase_path(_merged_name, root_build_dir),
+ ] + rebase_path(invoker.plist_templates, root_build_dir)
+ }
+
+ action(target_name) {
+ forward_variables_from(invoker,
+ [
+ "testonly",
+ "visibility",
+ ])
+ script = "//build/apple/plist_util.py"
+ sources = [ _merged_name ]
+ outputs = [ _output_name ]
+ args = [
+ "substitute",
+ "-f=" + invoker.format,
+ "-o=" + rebase_path(_output_name, root_build_dir),
+ "-t=" + rebase_path(_merged_name, root_build_dir),
+ ]
+ foreach(_substitution, invoker.substitutions) {
+ args += [ "-s=$_substitution" ]
+ }
+ deps = [ ":$_merge_target" ]
+ }
+}
diff --git a/third_party/libwebrtc/build/apple/convert_plist.gni b/third_party/libwebrtc/build/apple/convert_plist.gni
new file mode 100644
index 0000000000..a1134d9b31
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/convert_plist.gni
@@ -0,0 +1,41 @@
+# Copyright 2021 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.
+
+# Convert plist file to given format.
+#
+# Arguments
+#
+# source:
+# string, path to the plist file to convert
+#
+# output:
+# string, path to the converted plist, must be under $root_build_dir
+#
+# format:
+# string, the format to convert the plist to. Either "binary1" or "xml1".
+template("convert_plist") {
+ assert(defined(invoker.source), "source must be defined for $target_name")
+ assert(defined(invoker.output), "output must be defined for $target_name")
+ assert(defined(invoker.format), "format must be defined for $target_name")
+
+ action(target_name) {
+ forward_variables_from(invoker,
+ [
+ "visibility",
+ "testonly",
+ "deps",
+ ])
+
+ script = "//build/apple/plist_util.py"
+ sources = [ invoker.source ]
+ outputs = [ invoker.output ]
+ args = [
+ "merge",
+ "--format=${invoker.format}",
+ "-o",
+ rebase_path(invoker.output, root_build_dir),
+ rebase_path(invoker.source, root_build_dir),
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/build/apple/plist_util.py b/third_party/libwebrtc/build/apple/plist_util.py
new file mode 100644
index 0000000000..54cf46176b
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/plist_util.py
@@ -0,0 +1,265 @@
+# Copyright 2016 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.
+
+import argparse
+import codecs
+import plistlib
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import shlex
+
+if sys.version_info.major < 3:
+ basestring_compat = basestring
+else:
+ basestring_compat = str
+
+# Xcode substitutes variables like ${PRODUCT_NAME} or $(PRODUCT_NAME) when
+# compiling Info.plist. It also supports supports modifiers like :identifier
+# or :rfc1034identifier. SUBSTITUTION_REGEXP_LIST is a list of regular
+# expressions matching a variable substitution pattern with an optional
+# modifier, while INVALID_CHARACTER_REGEXP matches all characters that are
+# not valid in an "identifier" value (used when applying the modifier).
+INVALID_CHARACTER_REGEXP = re.compile(r'[_/\s]')
+SUBSTITUTION_REGEXP_LIST = (
+ re.compile(r'\$\{(?P<id>[^}]*?)(?P<modifier>:[^}]*)?\}'),
+ re.compile(r'\$\((?P<id>[^}]*?)(?P<modifier>:[^}]*)?\)'),
+)
+
+
+class SubstitutionError(Exception):
+ def __init__(self, key):
+ super(SubstitutionError, self).__init__()
+ self.key = key
+
+ def __str__(self):
+ return "SubstitutionError: {}".format(self.key)
+
+
+def InterpolateString(value, substitutions):
+ """Interpolates variable references into |value| using |substitutions|.
+
+ Inputs:
+ value: a string
+ substitutions: a mapping of variable names to values
+
+ Returns:
+ A new string with all variables references ${VARIABLES} replaced by their
+ value in |substitutions|. Raises SubstitutionError if a variable has no
+ substitution.
+ """
+
+ def repl(match):
+ variable = match.group('id')
+ if variable not in substitutions:
+ raise SubstitutionError(variable)
+ # Some values need to be identifier and thus the variables references may
+ # contains :modifier attributes to indicate how they should be converted
+ # to identifiers ("identifier" replaces all invalid characters by '_' and
+ # "rfc1034identifier" replaces them by "-" to make valid URI too).
+ modifier = match.group('modifier')
+ if modifier == ':identifier':
+ return INVALID_CHARACTER_REGEXP.sub('_', substitutions[variable])
+ elif modifier == ':rfc1034identifier':
+ return INVALID_CHARACTER_REGEXP.sub('-', substitutions[variable])
+ else:
+ return substitutions[variable]
+
+ for substitution_regexp in SUBSTITUTION_REGEXP_LIST:
+ value = substitution_regexp.sub(repl, value)
+ return value
+
+
+def Interpolate(value, substitutions):
+ """Interpolates variable references into |value| using |substitutions|.
+
+ Inputs:
+ value: a value, can be a dictionary, list, string or other
+ substitutions: a mapping of variable names to values
+
+ Returns:
+ A new value with all variables references ${VARIABLES} replaced by their
+ value in |substitutions|. Raises SubstitutionError if a variable has no
+ substitution.
+ """
+ if isinstance(value, dict):
+ return {k: Interpolate(v, substitutions) for k, v in value.items()}
+ if isinstance(value, list):
+ return [Interpolate(v, substitutions) for v in value]
+ if isinstance(value, basestring_compat):
+ return InterpolateString(value, substitutions)
+ return value
+
+
+def LoadPList(path):
+ """Loads Plist at |path| and returns it as a dictionary."""
+ if sys.version_info.major == 2:
+ fd, name = tempfile.mkstemp()
+ try:
+ subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
+ with os.fdopen(fd, 'rb') as f:
+ return plistlib.readPlist(f)
+ finally:
+ os.unlink(name)
+ else:
+ with open(path, 'rb') as f:
+ return plistlib.load(f)
+
+
+def SavePList(path, format, data):
+ """Saves |data| as a Plist to |path| in the specified |format|."""
+ # The below does not replace the destination file but update it in place,
+ # so if more than one hardlink points to destination all of them will be
+ # modified. This is not what is expected, so delete destination file if
+ # it does exist.
+ if os.path.exists(path):
+ os.unlink(path)
+ if sys.version_info.major == 2:
+ fd, name = tempfile.mkstemp()
+ try:
+ with os.fdopen(fd, 'wb') as f:
+ plistlib.writePlist(data, f)
+ subprocess.check_call(['plutil', '-convert', format, '-o', path, name])
+ finally:
+ os.unlink(name)
+ else:
+ with open(path, 'wb') as f:
+ plist_format = {'binary1': plistlib.FMT_BINARY, 'xml1': plistlib.FMT_XML}
+ plistlib.dump(data, f, fmt=plist_format[format])
+
+
+def MergePList(plist1, plist2):
+ """Merges |plist1| with |plist2| recursively.
+
+ Creates a new dictionary representing a Property List (.plist) files by
+ merging the two dictionary |plist1| and |plist2| recursively (only for
+ dictionary values). List value will be concatenated.
+
+ Args:
+ plist1: a dictionary representing a Property List (.plist) file
+ plist2: a dictionary representing a Property List (.plist) file
+
+ Returns:
+ A new dictionary representing a Property List (.plist) file by merging
+ |plist1| with |plist2|. If any value is a dictionary, they are merged
+ recursively, otherwise |plist2| value is used. If values are list, they
+ are concatenated.
+ """
+ result = plist1.copy()
+ for key, value in plist2.items():
+ if isinstance(value, dict):
+ old_value = result.get(key)
+ if isinstance(old_value, dict):
+ value = MergePList(old_value, value)
+ if isinstance(value, list):
+ value = plist1.get(key, []) + plist2.get(key, [])
+ result[key] = value
+ return result
+
+
+class Action(object):
+ """Class implementing one action supported by the script."""
+
+ @classmethod
+ def Register(cls, subparsers):
+ parser = subparsers.add_parser(cls.name, help=cls.help)
+ parser.set_defaults(func=cls._Execute)
+ cls._Register(parser)
+
+
+class MergeAction(Action):
+ """Class to merge multiple plist files."""
+
+ name = 'merge'
+ help = 'merge multiple plist files'
+
+ @staticmethod
+ def _Register(parser):
+ parser.add_argument('-o',
+ '--output',
+ required=True,
+ help='path to the output plist file')
+ parser.add_argument('-f',
+ '--format',
+ required=True,
+ choices=('xml1', 'binary1'),
+ help='format of the plist file to generate')
+ parser.add_argument(
+ '-x',
+ '--xcode-version',
+ help='version of Xcode, ignored (can be used to force rebuild)')
+ parser.add_argument('path', nargs="+", help='path to plist files to merge')
+
+ @staticmethod
+ def _Execute(args):
+ data = {}
+ for filename in args.path:
+ data = MergePList(data, LoadPList(filename))
+ SavePList(args.output, args.format, data)
+
+
+class SubstituteAction(Action):
+ """Class implementing the variable substitution in a plist file."""
+
+ name = 'substitute'
+ help = 'perform pattern substitution in a plist file'
+
+ @staticmethod
+ def _Register(parser):
+ parser.add_argument('-o',
+ '--output',
+ required=True,
+ help='path to the output plist file')
+ parser.add_argument('-t',
+ '--template',
+ required=True,
+ help='path to the template file')
+ parser.add_argument('-s',
+ '--substitution',
+ action='append',
+ default=[],
+ help='substitution rule in the format key=value')
+ parser.add_argument('-f',
+ '--format',
+ required=True,
+ choices=('xml1', 'binary1'),
+ help='format of the plist file to generate')
+ parser.add_argument(
+ '-x',
+ '--xcode-version',
+ help='version of Xcode, ignored (can be used to force rebuild)')
+
+ @staticmethod
+ def _Execute(args):
+ substitutions = {}
+ for substitution in args.substitution:
+ key, value = substitution.split('=', 1)
+ substitutions[key] = value
+ data = Interpolate(LoadPList(args.template), substitutions)
+ SavePList(args.output, args.format, data)
+
+
+def Main():
+ # Cache this codec so that plistlib can find it. See
+ # https://crbug.com/1005190#c2 for more details.
+ codecs.lookup('utf-8')
+
+ parser = argparse.ArgumentParser(description='manipulate plist files')
+ subparsers = parser.add_subparsers()
+
+ for action in [MergeAction, SubstituteAction]:
+ action.Register(subparsers)
+
+ args = parser.parse_args()
+ args.func(args)
+
+
+if __name__ == '__main__':
+ # TODO(https://crbug.com/941669): Temporary workaround until all scripts use
+ # python3 by default.
+ if sys.version_info[0] < 3:
+ os.execvp('python3', ['python3'] + sys.argv)
+ sys.exit(Main())
diff --git a/third_party/libwebrtc/build/apple/tweak_info_plist.gni b/third_party/libwebrtc/build/apple/tweak_info_plist.gni
new file mode 100644
index 0000000000..33f22ca2d0
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/tweak_info_plist.gni
@@ -0,0 +1,86 @@
+# Copyright 2016 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.
+
+import("//build/util/lastchange.gni")
+
+# Template to run the tweak_info_plist.py script on a plist.
+#
+# Arguments:
+#
+# info_plist:
+# (optional), string, the plist to tweak.
+#
+# info_plists:
+# (optional), list of string, the plist files to merge and tweak.
+#
+# args:
+# (optional), list of string, the arguments to pass to the
+# tweak_info_plist.py script.
+#
+# Callers should use get_target_outputs() to get the output name. One of
+# info_plist or info_plists must be specified.
+template("tweak_info_plist") {
+ _output_name = "$target_gen_dir/${target_name}_tweaked.plist"
+
+ if (defined(invoker.info_plists)) {
+ assert(!defined(invoker.info_plist),
+ "Cannot have both info_plist and info_plists for $target_name")
+
+ _source_name = "$target_gen_dir/${target_name}_merged.plist"
+ _deps = [ ":" + target_name + "_merge_plist" ]
+
+ action(target_name + "_merge_plist") {
+ forward_variables_from(invoker,
+ [
+ "testonly",
+ "deps",
+ ])
+ script = "//build/apple/plist_util.py"
+ sources = invoker.info_plists
+ outputs = [ _source_name ]
+ args = [
+ "merge",
+ "-f=xml1",
+ "-o=" + rebase_path(_source_name, root_build_dir),
+ ] + rebase_path(invoker.info_plists, root_build_dir)
+ }
+ } else {
+ assert(defined(invoker.info_plist),
+ "The info_plist must be specified in $target_name")
+
+ _source_name = invoker.info_plist
+ _deps = []
+ if (defined(invoker.deps)) {
+ _deps += invoker.deps
+ }
+ }
+
+ action(target_name) {
+ forward_variables_from(invoker,
+ [
+ "args",
+ "testonly",
+ ])
+ script = "//build/apple/tweak_info_plist.py"
+ inputs = [
+ script,
+ "//build/util/version.py",
+ lastchange_file,
+ "//chrome/VERSION",
+ ]
+ sources = [ _source_name ]
+ outputs = [ _output_name ]
+ if (!defined(args)) {
+ args = []
+ }
+ args += [
+ "--plist",
+ rebase_path(_source_name, root_build_dir),
+ "--output",
+ rebase_path(_output_name, root_build_dir),
+ "--platform=$current_os",
+ ]
+ deps = _deps
+ }
+}
diff --git a/third_party/libwebrtc/build/apple/tweak_info_plist.py b/third_party/libwebrtc/build/apple/tweak_info_plist.py
new file mode 100755
index 0000000000..76f64dc37c
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/tweak_info_plist.py
@@ -0,0 +1,447 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+#
+# Xcode supports build variable substitutions and CPP; sadly, that doesn't work
+# because:
+#
+# 1. Xcode wants to do the Info.plist work before it runs any build phases,
+# this means if we were to generate a .h file for INFOPLIST_PREFIX_HEADER
+# we'd have to put it in another target so it runs in time.
+# 2. Xcode also doesn't check to see if the header being used as a prefix for
+# the Info.plist has changed. So even if we updated it, it's only looking
+# at the modtime of the info.plist to see if that's changed.
+#
+# So, we work around all of this by making a script build phase that will run
+# during the app build, and simply update the info.plist in place. This way
+# by the time the app target is done, the info.plist is correct.
+#
+
+from __future__ import print_function
+
+import optparse
+import os
+import plistlib
+import re
+import subprocess
+import sys
+import tempfile
+
+TOP = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+
+
+def _ConvertPlist(source_plist, output_plist, fmt):
+ """Convert |source_plist| to |fmt| and save as |output_plist|."""
+ assert sys.version_info.major == 2, "Use plistlib directly in Python 3"
+ return subprocess.call(
+ ['plutil', '-convert', fmt, '-o', output_plist, source_plist])
+
+
+def _GetOutput(args):
+ """Runs a subprocess and waits for termination. Returns (stdout, returncode)
+ of the process. stderr is attached to the parent."""
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ stdout, _ = proc.communicate()
+ return stdout.decode('UTF-8'), proc.returncode
+
+
+def _RemoveKeys(plist, *keys):
+ """Removes a varargs of keys from the plist."""
+ for key in keys:
+ try:
+ del plist[key]
+ except KeyError:
+ pass
+
+
+def _ApplyVersionOverrides(version, keys, overrides, separator='.'):
+ """Applies version overrides.
+
+ Given a |version| string as "a.b.c.d" (assuming a default separator) with
+ version components named by |keys| then overrides any value that is present
+ in |overrides|.
+
+ >>> _ApplyVersionOverrides('a.b', ['major', 'minor'], {'minor': 'd'})
+ 'a.d'
+ """
+ if not overrides:
+ return version
+ version_values = version.split(separator)
+ for i, (key, value) in enumerate(zip(keys, version_values)):
+ if key in overrides:
+ version_values[i] = overrides[key]
+ return separator.join(version_values)
+
+
+def _GetVersion(version_format, values, overrides=None):
+ """Generates a version number according to |version_format| using the values
+ from |values| or |overrides| if given."""
+ result = version_format
+ for key in values:
+ if overrides and key in overrides:
+ value = overrides[key]
+ else:
+ value = values[key]
+ result = result.replace('@%s@' % key, value)
+ return result
+
+
+def _AddVersionKeys(plist, version_format_for_key, version=None,
+ overrides=None):
+ """Adds the product version number into the plist. Returns True on success and
+ False on error. The error will be printed to stderr."""
+ if not version:
+ # Pull in the Chrome version number.
+ VERSION_TOOL = os.path.join(TOP, 'build/util/version.py')
+ VERSION_FILE = os.path.join(TOP, 'chrome/VERSION')
+ (stdout, retval) = _GetOutput([
+ VERSION_TOOL, '-f', VERSION_FILE, '-t',
+ '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
+ ])
+
+ # If the command finished with a non-zero return code, then report the
+ # error up.
+ if retval != 0:
+ return False
+
+ version = stdout.strip()
+
+ # Parse the given version number, that should be in MAJOR.MINOR.BUILD.PATCH
+ # format (where each value is a number). Note that str.isdigit() returns
+ # True if the string is composed only of digits (and thus match \d+ regexp).
+ groups = version.split('.')
+ if len(groups) != 4 or not all(element.isdigit() for element in groups):
+ print('Invalid version string specified: "%s"' % version, file=sys.stderr)
+ return False
+ values = dict(zip(('MAJOR', 'MINOR', 'BUILD', 'PATCH'), groups))
+
+ for key in version_format_for_key:
+ plist[key] = _GetVersion(version_format_for_key[key], values, overrides)
+
+ # Return with no error.
+ return True
+
+
+def _DoSCMKeys(plist, add_keys):
+ """Adds the SCM information, visible in about:version, to property list. If
+ |add_keys| is True, it will insert the keys, otherwise it will remove them."""
+ scm_revision = None
+ if add_keys:
+ # Pull in the Chrome revision number.
+ VERSION_TOOL = os.path.join(TOP, 'build/util/version.py')
+ LASTCHANGE_FILE = os.path.join(TOP, 'build/util/LASTCHANGE')
+ (stdout, retval) = _GetOutput(
+ [VERSION_TOOL, '-f', LASTCHANGE_FILE, '-t', '@LASTCHANGE@'])
+ if retval:
+ return False
+ scm_revision = stdout.rstrip()
+
+ # See if the operation failed.
+ _RemoveKeys(plist, 'SCMRevision')
+ if scm_revision != None:
+ plist['SCMRevision'] = scm_revision
+ elif add_keys:
+ print('Could not determine SCM revision. This may be OK.', file=sys.stderr)
+
+ return True
+
+
+def _AddBreakpadKeys(plist, branding, platform, staging):
+ """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and
+ also requires the |branding| argument."""
+ plist['BreakpadReportInterval'] = '3600' # Deliberately a string.
+ plist['BreakpadProduct'] = '%s_%s' % (branding, platform)
+ plist['BreakpadProductDisplay'] = branding
+ if staging:
+ plist['BreakpadURL'] = 'https://clients2.google.com/cr/staging_report'
+ else:
+ plist['BreakpadURL'] = 'https://clients2.google.com/cr/report'
+
+ # These are both deliberately strings and not boolean.
+ plist['BreakpadSendAndExit'] = 'YES'
+ plist['BreakpadSkipConfirm'] = 'YES'
+
+
+def _RemoveBreakpadKeys(plist):
+ """Removes any set Breakpad keys."""
+ _RemoveKeys(plist, 'BreakpadURL', 'BreakpadReportInterval', 'BreakpadProduct',
+ 'BreakpadProductDisplay', 'BreakpadVersion',
+ 'BreakpadSendAndExit', 'BreakpadSkipConfirm')
+
+
+def _TagSuffixes():
+ # Keep this list sorted in the order that tag suffix components are to
+ # appear in a tag value. That is to say, it should be sorted per ASCII.
+ components = ('full', )
+ assert tuple(sorted(components)) == components
+
+ components_len = len(components)
+ combinations = 1 << components_len
+ tag_suffixes = []
+ for combination in range(0, combinations):
+ tag_suffix = ''
+ for component_index in range(0, components_len):
+ if combination & (1 << component_index):
+ tag_suffix += '-' + components[component_index]
+ tag_suffixes.append(tag_suffix)
+ return tag_suffixes
+
+
+def _AddKeystoneKeys(plist, bundle_identifier, base_tag):
+ """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and
+ also requires the |bundle_identifier| argument (com.example.product)."""
+ plist['KSVersion'] = plist['CFBundleShortVersionString']
+ plist['KSProductID'] = bundle_identifier
+ plist['KSUpdateURL'] = 'https://tools.google.com/service/update2'
+
+ _RemoveKeys(plist, 'KSChannelID')
+ if base_tag != '':
+ plist['KSChannelID'] = base_tag
+ for tag_suffix in _TagSuffixes():
+ if tag_suffix:
+ plist['KSChannelID' + tag_suffix] = base_tag + tag_suffix
+
+
+def _RemoveKeystoneKeys(plist):
+ """Removes any set Keystone keys."""
+ _RemoveKeys(plist, 'KSVersion', 'KSProductID', 'KSUpdateURL')
+
+ tag_keys = ['KSChannelID']
+ for tag_suffix in _TagSuffixes():
+ tag_keys.append('KSChannelID' + tag_suffix)
+ _RemoveKeys(plist, *tag_keys)
+
+
+def _AddGTMKeys(plist, platform):
+ """Adds the GTM metadata keys. This must be called AFTER _AddVersionKeys()."""
+ plist['GTMUserAgentID'] = plist['CFBundleName']
+ if platform == 'ios':
+ plist['GTMUserAgentVersion'] = plist['CFBundleVersion']
+ else:
+ plist['GTMUserAgentVersion'] = plist['CFBundleShortVersionString']
+
+
+def _RemoveGTMKeys(plist):
+ """Removes any set GTM metadata keys."""
+ _RemoveKeys(plist, 'GTMUserAgentID', 'GTMUserAgentVersion')
+
+
+def Main(argv):
+ parser = optparse.OptionParser('%prog [options]')
+ parser.add_option('--plist',
+ dest='plist_path',
+ action='store',
+ type='string',
+ default=None,
+ help='The path of the plist to tweak.')
+ parser.add_option('--output', dest='plist_output', action='store',
+ type='string', default=None, help='If specified, the path to output ' + \
+ 'the tweaked plist, rather than overwriting the input.')
+ parser.add_option('--breakpad',
+ dest='use_breakpad',
+ action='store',
+ type='int',
+ default=False,
+ help='Enable Breakpad [1 or 0]')
+ parser.add_option(
+ '--breakpad_staging',
+ dest='use_breakpad_staging',
+ action='store_true',
+ default=False,
+ help='Use staging breakpad to upload reports. Ignored if --breakpad=0.')
+ parser.add_option('--keystone',
+ dest='use_keystone',
+ action='store',
+ type='int',
+ default=False,
+ help='Enable Keystone [1 or 0]')
+ parser.add_option('--keystone-base-tag',
+ default='',
+ help='Base Keystone tag to set')
+ parser.add_option('--scm',
+ dest='add_scm_info',
+ action='store',
+ type='int',
+ default=True,
+ help='Add SCM metadata [1 or 0]')
+ parser.add_option('--branding',
+ dest='branding',
+ action='store',
+ type='string',
+ default=None,
+ help='The branding of the binary')
+ parser.add_option('--bundle_id',
+ dest='bundle_identifier',
+ action='store',
+ type='string',
+ default=None,
+ help='The bundle id of the binary')
+ parser.add_option('--platform',
+ choices=('ios', 'mac'),
+ default='mac',
+ help='The target platform of the bundle')
+ parser.add_option('--add-gtm-metadata',
+ dest='add_gtm_info',
+ action='store',
+ type='int',
+ default=False,
+ help='Add GTM metadata [1 or 0]')
+ # TODO(crbug.com/1140474): Remove once iOS 14.2 reaches mass adoption.
+ parser.add_option('--lock-to-version',
+ help='Set CFBundleVersion to given value + @MAJOR@@PATH@')
+ parser.add_option(
+ '--version-overrides',
+ action='append',
+ help='Key-value pair to override specific component of version '
+ 'like key=value (can be passed multiple time to configure '
+ 'more than one override)')
+ parser.add_option('--format',
+ choices=('binary1', 'xml1'),
+ default='xml1',
+ help='Format to use when writing property list '
+ '(default: %(default)s)')
+ parser.add_option('--version',
+ dest='version',
+ action='store',
+ type='string',
+ default=None,
+ help='The version string [major.minor.build.patch]')
+ (options, args) = parser.parse_args(argv)
+
+ if len(args) > 0:
+ print(parser.get_usage(), file=sys.stderr)
+ return 1
+
+ if not options.plist_path:
+ print('No --plist specified.', file=sys.stderr)
+ return 1
+
+ # Read the plist into its parsed format. Convert the file to 'xml1' as
+ # plistlib only supports that format in Python 2.7.
+ with tempfile.NamedTemporaryFile() as temp_info_plist:
+ if sys.version_info.major == 2:
+ retcode = _ConvertPlist(options.plist_path, temp_info_plist.name, 'xml1')
+ if retcode != 0:
+ return retcode
+ plist = plistlib.readPlist(temp_info_plist.name)
+ else:
+ with open(options.plist_path, 'rb') as f:
+ plist = plistlib.load(f)
+
+ # Convert overrides.
+ overrides = {}
+ if options.version_overrides:
+ for pair in options.version_overrides:
+ if not '=' in pair:
+ print('Invalid value for --version-overrides:', pair, file=sys.stderr)
+ return 1
+ key, value = pair.split('=', 1)
+ overrides[key] = value
+ if key not in ('MAJOR', 'MINOR', 'BUILD', 'PATCH'):
+ print('Unsupported key for --version-overrides:', key, file=sys.stderr)
+ return 1
+
+ if options.platform == 'mac':
+ version_format_for_key = {
+ # Add public version info so "Get Info" works.
+ 'CFBundleShortVersionString': '@MAJOR@.@MINOR@.@BUILD@.@PATCH@',
+
+ # Honor the 429496.72.95 limit. The maximum comes from splitting
+ # 2^32 - 1 into 6, 2, 2 digits. The limitation was present in Tiger,
+ # but it could have been fixed in later OS release, but hasn't been
+ # tested (it's easy enough to find out with "lsregister -dump).
+ # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html
+ # BUILD will always be an increasing value, so BUILD_PATH gives us
+ # something unique that meetings what LS wants.
+ 'CFBundleVersion': '@BUILD@.@PATCH@',
+ }
+ else:
+ # TODO(crbug.com/1140474): Remove once iOS 14.2 reaches mass adoption.
+ if options.lock_to_version:
+ # Pull in the PATCH number and format it to 3 digits.
+ VERSION_TOOL = os.path.join(TOP, 'build/util/version.py')
+ VERSION_FILE = os.path.join(TOP, 'chrome/VERSION')
+ (stdout,
+ retval) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t', '@PATCH@'])
+ if retval != 0:
+ return 2
+ patch = '{:03d}'.format(int(stdout))
+ version_format_for_key = {
+ 'CFBundleShortVersionString': '@MAJOR@.@BUILD@.@PATCH@',
+ 'CFBundleVersion': options.lock_to_version + '.@MAJOR@' + patch
+ }
+ else:
+ version_format_for_key = {
+ 'CFBundleShortVersionString': '@MAJOR@.@BUILD@.@PATCH@',
+ 'CFBundleVersion': '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
+ }
+
+ if options.use_breakpad:
+ version_format_for_key['BreakpadVersion'] = \
+ '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
+
+ # Insert the product version.
+ if not _AddVersionKeys(plist,
+ version_format_for_key,
+ version=options.version,
+ overrides=overrides):
+ return 2
+
+ # Add Breakpad if configured to do so.
+ if options.use_breakpad:
+ if options.branding is None:
+ print('Use of Breakpad requires branding.', file=sys.stderr)
+ return 1
+ # Map "target_os" passed from gn via the --platform parameter
+ # to the platform as known by breakpad.
+ platform = {'mac': 'Mac', 'ios': 'iOS'}[options.platform]
+ _AddBreakpadKeys(plist, options.branding, platform,
+ options.use_breakpad_staging)
+ else:
+ _RemoveBreakpadKeys(plist)
+
+ # Add Keystone if configured to do so.
+ if options.use_keystone:
+ if options.bundle_identifier is None:
+ print('Use of Keystone requires the bundle id.', file=sys.stderr)
+ return 1
+ _AddKeystoneKeys(plist, options.bundle_identifier,
+ options.keystone_base_tag)
+ else:
+ _RemoveKeystoneKeys(plist)
+
+ # Adds or removes any SCM keys.
+ if not _DoSCMKeys(plist, options.add_scm_info):
+ return 3
+
+ # Add GTM metadata keys.
+ if options.add_gtm_info:
+ _AddGTMKeys(plist, options.platform)
+ else:
+ _RemoveGTMKeys(plist)
+
+ output_path = options.plist_path
+ if options.plist_output is not None:
+ output_path = options.plist_output
+
+ # Now that all keys have been mutated, rewrite the file.
+ # Convert Info.plist to the format requested by the --format flag. Any
+ # format would work on Mac but iOS requires specific format.
+ if sys.version_info.major == 2:
+ with tempfile.NamedTemporaryFile() as temp_info_plist:
+ plistlib.writePlist(plist, temp_info_plist.name)
+ return _ConvertPlist(temp_info_plist.name, output_path, options.format)
+ with open(output_path, 'wb') as f:
+ plist_format = {'binary1': plistlib.FMT_BINARY, 'xml1': plistlib.FMT_XML}
+ plistlib.dump(plist, f, fmt=plist_format[options.format])
+
+
+if __name__ == '__main__':
+ # TODO(https://crbug.com/941669): Temporary workaround until all scripts use
+ # python3 by default.
+ if sys.version_info[0] < 3:
+ os.execvp('python3', ['python3'] + sys.argv)
+ sys.exit(Main(sys.argv[1:]))
diff --git a/third_party/libwebrtc/build/apple/write_pkg_info.py b/third_party/libwebrtc/build/apple/write_pkg_info.py
new file mode 100644
index 0000000000..8d07cdb311
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/write_pkg_info.py
@@ -0,0 +1,54 @@
+# Copyright 2016 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.
+
+import argparse
+import os
+import plist_util
+import sys
+
+# This script creates a PkgInfo file for an OS X .app bundle's plist.
+# Usage: python write_pkg_info.py --plist Foo.app/Contents/Info.plist \
+# --output Foo.app/Contents/PkgInfo
+
+
+def Main():
+ parser = argparse.ArgumentParser(
+ description='A script to write PkgInfo files for .app bundles.')
+ parser.add_argument('--plist',
+ required=True,
+ help='Path to the Info.plist for the .app.')
+ parser.add_argument('--output',
+ required=True,
+ help='Path to the desired output file.')
+ args = parser.parse_args()
+
+ # Remove the output if it exists already.
+ if os.path.exists(args.output):
+ os.unlink(args.output)
+
+ plist = plist_util.LoadPList(args.plist)
+ package_type = plist['CFBundlePackageType']
+ if package_type != 'APPL':
+ raise ValueError('Expected CFBundlePackageType to be %s, got %s' % \
+ ('APPL', package_type))
+
+ # The format of PkgInfo is eight characters, representing the bundle type
+ # and bundle signature, each four characters. If that is missing, four
+ # '?' characters are used instead.
+ signature_code = plist.get('CFBundleSignature', '????')
+ if len(signature_code) != 4:
+ raise ValueError('CFBundleSignature should be exactly four characters, ' +
+ 'got %s' % signature_code)
+
+ with open(args.output, 'w') as fp:
+ fp.write('%s%s' % (package_type, signature_code))
+ return 0
+
+
+if __name__ == '__main__':
+ # TODO(https://crbug.com/941669): Temporary workaround until all scripts use
+ # python3 by default.
+ if sys.version_info[0] < 3:
+ os.execvp('python3', ['python3'] + sys.argv)
+ sys.exit(Main())
diff --git a/third_party/libwebrtc/build/apple/xcrun.py b/third_party/libwebrtc/build/apple/xcrun.py
new file mode 100755
index 0000000000..71bf50c352
--- /dev/null
+++ b/third_party/libwebrtc/build/apple/xcrun.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python3
+# Copyright 2020 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.
+"""
+Wrapper around xcrun adding support for --developer-dir parameter to set
+the DEVELOPER_DIR environment variable, and for converting paths relative
+to absolute (since this is required by most of the tool run via xcrun).
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+def xcrun(command, developer_dir):
+ environ = dict(os.environ)
+ if developer_dir:
+ environ['DEVELOPER_DIR'] = os.path.abspath(developer_dir)
+
+ processed_args = ['/usr/bin/xcrun']
+ for arg in command:
+ if os.path.exists(arg):
+ arg = os.path.abspath(arg)
+ processed_args.append(arg)
+
+ process = subprocess.Popen(processed_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ env=environ)
+
+ stdout, stderr = process.communicate()
+ sys.stdout.write(stdout)
+ if process.returncode:
+ sys.stderr.write(stderr)
+ sys.exit(process.returncode)
+
+
+def main(args):
+ parser = argparse.ArgumentParser(add_help=False)
+ parser.add_argument(
+ '--developer-dir',
+ help='path to developer dir to use for the invocation of xcrun')
+
+ parsed, remaining_args = parser.parse_known_args(args)
+ xcrun(remaining_args, parsed.developer_dir)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])