-
Notifications
You must be signed in to change notification settings - Fork 272
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add xctrunnertool to create test bundles
- Loading branch information
1 parent
5699172
commit 8ae0d63
Showing
9 changed files
with
459 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
""" | ||
Rule for merging multiple test targets into a single XCTRunner.app bundle. | ||
""" | ||
|
||
load("@build_bazel_rules_apple//apple:providers.bzl", "AppleBundleInfo") | ||
|
||
def _ios_test_runner_bundle_impl(ctx): | ||
# Get test target info | ||
xctrunner_output = ctx.label.name + "_xctrunner" | ||
bundle_info = [target[AppleBundleInfo] for target in ctx.attr.test_targets] | ||
xctests = [info.archive for info in bundle_info] # xctest bundles | ||
infoplist = [info.infoplist for info in bundle_info] # Info.plist files | ||
merged_bundle = ctx.actions.declare_directory(xctrunner_output) # output dir | ||
|
||
# Args for _make_xctrunner | ||
arguments = ctx.actions.args() | ||
arguments.add("--name", ctx.label.name) | ||
arguments.add("--platform", ctx.attr.platform) | ||
|
||
# absolute paths to xctest bundles | ||
xctest_paths = [xctest.path for xctest in xctests] | ||
arguments.add_all( | ||
xctest_paths, | ||
before_each = "--xctest", | ||
expand_directories = False, | ||
) | ||
|
||
# app bundle output path | ||
arguments.add("--output", merged_bundle.path) | ||
|
||
ctx.actions.run( | ||
inputs = depset(xctests + infoplist), | ||
outputs = [merged_bundle], | ||
executable = ctx.executable._make_xctrunner, | ||
arguments = [arguments], | ||
mnemonic = "MakeXCTRunner", | ||
) | ||
|
||
return DefaultInfo(files = depset([merged_bundle])) | ||
|
||
ios_test_runner_bundle = rule( | ||
implementation = _ios_test_runner_bundle_impl, | ||
attrs = { | ||
"test_targets": attr.label_list( | ||
mandatory = True, | ||
providers = [ | ||
AppleBundleInfo, | ||
], | ||
doc = "List of ios_ui_test targets to merge.", | ||
), | ||
"platform": attr.string( | ||
default = "iPhoneOS.platform", | ||
mandatory = False, | ||
doc = "Platform to bundle for. Defaults to iPhoneOS.platform.", | ||
), | ||
"_make_xctrunner": attr.label( | ||
default = Label("//tools/snoozel/scripts/make_xctrunner:run"), | ||
executable = True, | ||
cfg = "exec", | ||
doc = "An executable binary that can merge separate xctest into a single XCTestRunner bundle.", | ||
), | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
py_library( | ||
name = "lib", | ||
srcs = glob(["lib/*.py"]), | ||
imports = ["."], | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
py_binary( | ||
name = "run", | ||
srcs = ["run.py"], | ||
imports = [ | ||
".", | ||
], | ||
visibility = ["//visibility:public"], | ||
deps = [":lib"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#!/usr/bin/env python3 | ||
|
||
""" | ||
List of dependencies (frameworks, private frameworks, dylibs, etc.) | ||
to copy to the test bundle. | ||
""" | ||
|
||
FRAMEWORK_DEPS = [ | ||
"XCTest.framework", | ||
"Testing.framework", | ||
] | ||
|
||
PRIVATE_FRAMEWORK_DEPS = [ | ||
"XCTAutomationSupport.framework", | ||
"XCTestCore.framework", | ||
"XCTestSupport.framework", | ||
"XCUIAutomation.framework", | ||
"XCUnit.framework", | ||
] | ||
|
||
DYLIB_DEPS = [ | ||
"libXCTestBundleInject.dylib", | ||
"libXCTestSwiftSupport.dylib", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import shutil | ||
from lib.shell import run_shell_command | ||
|
||
|
||
class LipoUtil: | ||
"Lipo utility class." | ||
|
||
def __init__(self): | ||
self.lipo_path = shutil.which("lipo") | ||
|
||
def has_arch(self, bin_path: str, arch: str) -> bool: | ||
"Returns True if the given binary has the given arch." | ||
cmd = f"{self.lipo_path} -info {bin_path}" | ||
output = run_shell_command(cmd, check_status=False) | ||
return arch in output | ||
|
||
def remove_arch(self, bin_path: str, arch: str): | ||
"Removes the given arch from the binary." | ||
if self.has_arch(bin_path, arch): | ||
cmd = f"{self.lipo_path} {bin_path} -remove {arch} -output {bin_path}" | ||
output = run_shell_command(cmd) | ||
print(output) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import logging | ||
import os | ||
import sys | ||
|
||
|
||
class StreamToLogger(object): | ||
""" | ||
Fake file-like stream object that redirects writes to a logger instance. | ||
""" | ||
|
||
def __init__(self, logger, level): | ||
self.logger = logger | ||
self.level = level | ||
self.linebuf = "" | ||
|
||
def write(self, buf): | ||
"Writes to file" | ||
for line in buf.rstrip().splitlines(): | ||
self.logger.log(self.level, line.rstrip()) | ||
|
||
def flush(self): | ||
"Flushes IO buffer" | ||
pass | ||
|
||
|
||
class Logger: | ||
"Logger class." | ||
|
||
def __init__(self, filename: str, level: str = "INFO"): | ||
logging.basicConfig( | ||
format="%(asctime)s MakeXCTRunner %(levelname)-8s %(message)s", | ||
level=level, # set at the step level as an env var | ||
datefmt="%Y-%m-%d %H:%M:%S %z", | ||
filename=filename, | ||
) | ||
|
||
# Add console logger in addition to a file logger | ||
console = logging.StreamHandler() | ||
lvl = (os.environ.get("CONSOLE_LOG_LEVEL") or "info").upper() | ||
console.setLevel(lvl) | ||
formatter = logging.Formatter( | ||
"%(asctime)s MakeXCTRunner %(levelname)-8s %(message)s" | ||
) | ||
console.setFormatter(formatter) | ||
logging.getLogger("").addHandler(console) | ||
|
||
def get(self, name: str) -> logging.Logger: | ||
"Returns logger with the given name." | ||
log = logging.getLogger(name) | ||
sys.stderr = StreamToLogger(log, logging.ERROR) | ||
return log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from dataclasses import dataclass | ||
from typing import List | ||
import os | ||
|
||
|
||
@dataclass | ||
class Configuration: | ||
"Configuration for the generator" | ||
name: str | ||
xctests: List[str] | ||
platform: str | ||
output: str | ||
xcode_path: str | ||
xctrunner_name: str = "XCTRunner" | ||
xctrunner_app = "XCTRunner.app" | ||
output_dir: str = "" | ||
developer_dir: str = "" | ||
libraries_dir: str = "" | ||
frameworks_dir: str = "" | ||
private_frameworks_dir: str = "" | ||
dylib_dir: str = "" | ||
xctrunner_app_name: str = "" | ||
xctrunner_path: str = "" | ||
xctrunner_template_path: str = "" | ||
xctrunner_bundle_identifier: str = "" | ||
xctrunner_info_plist_path: str = "" | ||
|
||
def __post_init__(self): | ||
self.developer_dir = f"{self.xcode_path}/Platforms/{self.platform}/Developer" | ||
self.libraries_dir = f"{self.developer_dir}/Library" | ||
self.frameworks_dir = f"{self.libraries_dir}/Frameworks" | ||
self.private_frameworks_dir = f"{self.libraries_dir}/PrivateFrameworks" | ||
self.dylib_dir = f"{self.developer_dir}/usr/lib" | ||
self.xctrunner_template_path = ( | ||
f"{self.libraries_dir}/Xcode/Agents/XCTRunner.app" | ||
) | ||
self.xctrunner_bundle_identifier = f"com.apple.test.{self.xctrunner_name}" | ||
self.output_dir = f"{os.path.dirname(self.output)}/{self.name}" | ||
self.xctrunner_path = f"{self.output_dir}/{self.xctrunner_app}" | ||
self.xctrunner_info_plist_path = f"{self.xctrunner_path}/Info.plist" | ||
|
||
# Create the output directory if missing | ||
os.makedirs(self.output_dir, exist_ok=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import plistlib | ||
|
||
|
||
class PlistUtil: | ||
"""Plist utility class.""" | ||
|
||
def __init__(self, plist_path): | ||
self.plist_path = plist_path | ||
with open(plist_path, "rb") as content: | ||
self.plist = plistlib.load(content) | ||
|
||
def update(self, key, value): | ||
"Updates given plist key with given value." | ||
self.plist[key] = value | ||
plistlib.dump(self.plist, open(self.plist_path, "wb")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import logging | ||
import subprocess | ||
|
||
|
||
def run_shell_command(command: str, check_status: bool = True) -> str: | ||
"Runs given shell command and returns stdout output." | ||
log = logging.getLogger(__name__) | ||
try: | ||
log.debug("Running shell command: %s", command) | ||
output = subprocess.run(command, shell=True, check=check_status, capture_output=True).stdout | ||
return output.decode("utf-8").strip() | ||
except subprocess.CalledProcessError as e: | ||
log.error("Shell command failed: %s", e) | ||
raise e |
Oops, something went wrong.