2021-10-23 14:38:22 -05:00

92 lines
3.2 KiB
Python
Executable File

# Released under the MIT License. See LICENSE for details.
#
"""Fetch and cache xcode project build paths.
This saves the few seconds it normally would take to fire up xcodebuild
and filter its output.
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
import time
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any, Optional
def project_build_path(projroot: str, project_path: str,
configuration: str) -> str:
"""Main script entry point."""
# pylint: disable=too-many-locals
config_path = os.path.join(projroot, '.cache', 'xcode_build_path')
out_path = None
config: dict[str, dict[str, Any]] = {}
build_dir: Optional[str] = None
try:
if os.path.exists(config_path):
with open(config_path, encoding='utf-8') as infile:
config = json.loads(infile.read())
if (project_path in config
and configuration in config[project_path]):
# Ok we've found a build-dir entry for this project; now if it
# exists on disk and all timestamps within it are decently
# close to the one we've got recorded, lets use it.
# (Anything using this script should also be building
# stuff there so mod times should be pretty recent; if not
# then its worth re-caching to be sure.)
build_dir = config[project_path][configuration]['build_dir']
timestamp = config[project_path][configuration]['timestamp']
assert build_dir is not None
if os.path.isdir(build_dir):
use_cached = True
# if its been over a day since we cached this, renew it
now = time.time()
if abs(now - timestamp) > 60 * 60 * 24:
use_cached = False
if use_cached:
out_path = build_dir
except Exception:
import traceback
print('EXCEPTION checking cached build path', file=sys.stderr)
traceback.print_exc()
out_path = None
# If we don't have a path at this point we look it up and cache it.
if out_path is None:
print('Caching xcode build path...', file=sys.stderr)
output = subprocess.check_output([
'xcodebuild', '-project', project_path, '-showBuildSettings',
'-configuration', configuration
]).decode('utf-8')
prefix = 'TARGET_BUILD_DIR = '
lines = [
l for l in output.splitlines() if l.strip().startswith(prefix)
]
if len(lines) != 1:
raise Exception(
'TARGET_BUILD_DIR not found in xcodebuild settings output')
build_dir = lines[0].replace(prefix, '').strip()
if project_path not in config:
config[project_path] = {}
config[project_path][configuration] = {
'build_dir': build_dir,
'timestamp': time.time()
}
os.makedirs(os.path.dirname(config_path), exist_ok=True)
with open(config_path, 'w', encoding='utf-8') as outfile:
outfile.write(json.dumps(config))
assert build_dir is not None
return build_dir