diff options
Diffstat (limited to 'third_party/libwebrtc/build/apple')
-rw-r--r-- | third_party/libwebrtc/build/apple/OWNERS | 4 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/README.md | 12 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/apple_info_plist.gni | 60 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/compile_entitlements.gni | 51 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/compile_plist.gni | 76 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/convert_plist.gni | 41 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/plist_util.py | 265 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/tweak_info_plist.gni | 86 | ||||
-rwxr-xr-x | third_party/libwebrtc/build/apple/tweak_info_plist.py | 447 | ||||
-rw-r--r-- | third_party/libwebrtc/build/apple/write_pkg_info.py | 54 | ||||
-rwxr-xr-x | third_party/libwebrtc/build/apple/xcrun.py | 52 |
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:]) |