159 lines
5.0 KiB
Python
Executable File
159 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright 2020 The MediaPipe Authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# Lint as: python3
|
|
"""This script is used to set up automatic provisioning for iOS examples.
|
|
|
|
It scans the provisioning profiles used by Xcode, looking for one matching the
|
|
application identifier for each example app. If found, it symlinks the profile
|
|
in the appropriate location for Bazel to find it.
|
|
|
|
It also checks whether the bundle_id.bzl file has a placeholder bundle ID, and
|
|
replaces it with a unique ID if so.
|
|
"""
|
|
|
|
import os
|
|
import plistlib
|
|
import re
|
|
import subprocess
|
|
import uuid
|
|
|
|
# This script is meant to be located in the MediaPipe iOS examples directory
|
|
# root. The logic below will have to be changed if the directory structure is
|
|
# reorganized.
|
|
examples_ios = os.path.dirname(os.path.realpath(__file__))
|
|
example_names = {
|
|
f for f in os.listdir(examples_ios)
|
|
if os.path.isdir(os.path.join(examples_ios, f))
|
|
}
|
|
|
|
|
|
def configure_bundle_id_prefix(
|
|
bundle_id_bzl=os.path.join(examples_ios, "bundle_id.bzl")) -> str:
|
|
"""Configures the bundle id prefix to use.
|
|
|
|
Gets the bundle id prefix in use from bundle_id.bzl; sets up a unique
|
|
prefix if not already set.
|
|
|
|
Args:
|
|
bundle_id_bzl: Path to the bzl file where the bundle id is stored.
|
|
|
|
Returns:
|
|
The bundle id prefix to use.
|
|
|
|
Raises:
|
|
Exception: If parsing of bundle_id.bzl fails.
|
|
"""
|
|
bundle_id_re = re.compile(
|
|
r'^BUNDLE_ID_PREFIX\s*=\s*"(.*)"', flags=re.MULTILINE)
|
|
|
|
with open(bundle_id_bzl, "r") as f:
|
|
contents = f.read()
|
|
match = bundle_id_re.search(contents)
|
|
if not match:
|
|
raise Exception("could not find BUNDLE_ID_PREFIX")
|
|
|
|
bundle_id_prefix = match.group(1)
|
|
# The default value contains a *, which is an invalid character in bundle IDs.
|
|
if "*" in bundle_id_prefix:
|
|
bundle_id_prefix = str(uuid.uuid4()) + ".mediapipe.examples"
|
|
contents = contents[:match.start(1)] + bundle_id_prefix + contents[match
|
|
.end(1):]
|
|
with open(bundle_id_bzl, "w") as f:
|
|
f.write(contents)
|
|
print("Set up a unique bundle ID prefix: " + bundle_id_prefix)
|
|
|
|
return bundle_id_prefix
|
|
|
|
|
|
def get_app_id(profile_path) -> str:
|
|
try:
|
|
plist = subprocess.check_output(
|
|
["security", "cms", "-D", "-i", profile_path])
|
|
profile = plistlib.loads(plist)
|
|
return profile["Entitlements"]["application-identifier"]
|
|
except Exception: # pylint: disable=broad-except
|
|
return None
|
|
|
|
|
|
def update_symlink(target_path, link_path):
|
|
if os.path.islink(link_path):
|
|
print(f" Removing existing symlink at {link_path}")
|
|
os.remove(link_path)
|
|
elif os.path.exists(link_path):
|
|
print(f" Unexpected existing file at {link_path}; skipping")
|
|
return
|
|
os.symlink(target_path, link_path)
|
|
print(f" Created symlink to {target_path} at {link_path}")
|
|
|
|
|
|
def process_profile(profile_path, our_app_id_re):
|
|
"""Processes one mobileprovision file.
|
|
|
|
Checks if its app ID matches one of our example apps, and symlinks it in the
|
|
appropriate location if so.
|
|
|
|
Args:
|
|
profile_path: Path to the mobileprovision file.
|
|
our_app_id_re: Regular expression to extract the example name from one of
|
|
out app ids.
|
|
"""
|
|
app_id = get_app_id(profile_path)
|
|
if not app_id:
|
|
print(f"Could not parse '{profile_path}', skipping")
|
|
return
|
|
match = our_app_id_re.match(app_id)
|
|
if not match:
|
|
return
|
|
app_name = match.group(1)
|
|
app_dir_name = app_name.lower()
|
|
if app_dir_name not in example_names:
|
|
print(f"The app id '{app_id}' has our prefix, but does not seem to match " +
|
|
"any of our examples. Skipping.")
|
|
return
|
|
|
|
print(f"Found profile for {app_name}")
|
|
|
|
link_path = os.path.join(examples_ios, app_dir_name,
|
|
"provisioning_profile.mobileprovision")
|
|
update_symlink(profile_path, link_path)
|
|
|
|
|
|
def main():
|
|
bundle_id_prefix = configure_bundle_id_prefix()
|
|
our_app_id_re = re.compile(r"[0-9A-Z]+\." + re.escape(bundle_id_prefix) +
|
|
r"\.(.*)")
|
|
|
|
profile_dir = os.path.expanduser(
|
|
"~/Library/MobileDevice/Provisioning Profiles")
|
|
if not os.path.isdir(profile_dir):
|
|
print(f"Could not find provisioning profiles directory at {profile_dir}")
|
|
return 2
|
|
|
|
print(
|
|
f"Looking for profiles for app ids with prefix '{bundle_id_prefix}' in '{profile_dir}'"
|
|
)
|
|
|
|
for name in os.listdir(profile_dir):
|
|
if not name.endswith(".mobileprovision"):
|
|
continue
|
|
profile_path = os.path.join(profile_dir, name)
|
|
process_profile(profile_path, our_app_id_re)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|