Skip to content

Add StoreKit Configuration support to Xcode Schemes. #3185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/bazel.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ Defines the Profile action.

<pre>
xcschemes.run(<a href="#xcschemes.run-args">args</a>, <a href="#xcschemes.run-build_targets">build_targets</a>, <a href="#xcschemes.run-diagnostics">diagnostics</a>, <a href="#xcschemes.run-env">env</a>, <a href="#xcschemes.run-env_include_defaults">env_include_defaults</a>, <a href="#xcschemes.run-launch_target">launch_target</a>,
<a href="#xcschemes.run-xcode_configuration">xcode_configuration</a>)
<a href="#xcschemes.run-xcode_configuration">xcode_configuration</a>, <a href="#xcschemes.run-storekit_configuration">storekit_configuration</a>)
</pre>

Defines the Run action.
Expand All @@ -496,6 +496,7 @@ Defines the Run action.
| <a id="xcschemes.run-env_include_defaults"></a>env_include_defaults | Whether to include the rules_xcodeproj provided default Bazel environment variables (e.g. `BUILD_WORKING_DIRECTORY` and `BUILD_WORKSPACE_DIRECTORY`), in addition to any set by [`env`](#xcschemes.run-env). This does not apply to [`xcschemes.launch_path`](#xcschemes.launch_path)s. | `True` |
| <a id="xcschemes.run-launch_target"></a>launch_target | The target to launch when running.<br><br>Can be `None`, a label string, a value returned by [`xcschemes.launch_target`](#xcschemes.launch_target), or a value returned by [`xcschemes.launch_path`](#xcschemes.launch_path). If a label string, `xcschemes.launch_target(label_str)` will be used. If `None`, `xcschemes.launch_target()` will be used, which means no launch target will be set (i.e. the `Executable` dropdown will be set to `None`). | `None` |
| <a id="xcschemes.run-xcode_configuration"></a>xcode_configuration | The name of the Xcode configuration to use to build the targets referenced in the Run action (i.e in the [`build_targets`](#xcschemes.run-build_targets) and [`launch_target`](#xcschemes.run-launch_target) attributes).<br><br>If not set, the value of [`xcodeproj.default_xcode_configuration`](#xcodeproj-default_xcode_configuration) is used. | `None` |
| <a id="xcschemes.run-storekit_configuration"></a>storekit_configuration | a label that points to a storekit configuration file. | `None` |


<a id="xcschemes.scheme"></a>
Expand Down Expand Up @@ -757,7 +758,8 @@ A `struct` representing scheme's diagnostics.
## xcode_schemes.launch_action

<pre>
xcode_schemes.launch_action(<a href="#xcode_schemes.launch_action-target">target</a>, <a href="#xcode_schemes.launch_action-args">args</a>, <a href="#xcode_schemes.launch_action-build_configuration">build_configuration</a>, <a href="#xcode_schemes.launch_action-diagnostics">diagnostics</a>, <a href="#xcode_schemes.launch_action-env">env</a>, <a href="#xcode_schemes.launch_action-working_directory">working_directory</a>)
xcode_schemes.launch_action(<a href="#xcode_schemes.launch_action-target">target</a>, <a href="#xcode_schemes.launch_action-args">args</a>, <a href="#xcode_schemes.launch_action-build_configuration">build_configuration</a>, <a href="#xcode_schemes.launch_action-diagnostics">diagnostics</a>, <a href="#xcode_schemes.launch_action-env">env</a>, <a href="#xcode_schemes.launch_action-working_directory">working_directory</a>,
<a href="#xcode_schemes.launch_action-storekit_configuration">storekit_configuration</a>)
</pre>

Constructs a launch action for an Xcode scheme.
Expand All @@ -773,6 +775,7 @@ Constructs a launch action for an Xcode scheme.
| <a id="xcode_schemes.launch_action-diagnostics"></a>diagnostics | Optional. A value returned by `xcode_schemes.diagnostics`. | `None` |
| <a id="xcode_schemes.launch_action-env"></a>env | Optional. A `dict` of `string` values that will be set as environment variables when the target is executed. | `None` |
| <a id="xcode_schemes.launch_action-working_directory"></a>working_directory | Optional. A `string` that will be set as the custom working directory in the Xcode scheme's launch action. Relative paths will be relative to the value of `target`'s `BUILT_PRODUCTS_DIR`, which is unique to it. | `None` |
| <a id="xcode_schemes.launch_action-storekit_configuration"></a>storekit_configuration | Optional. A `string` that will be set as the custom StoreKit configuration in the Xcode scheme's launch action. This should be a path relative to the workspace root. | `None` |

**RETURNS**

Expand Down
1 change: 1 addition & 0 deletions test/internal/xcode_schemes/model_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ def _launch_action_test(ctx):
diagnostics = None,
env = env,
working_directory = None,
storekit_configuration = None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this alphabetical.

)
asserts.equals(test_env, expected, actual)

Expand Down
3 changes: 3 additions & 0 deletions test/internal/xcschemes/info_constructors_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ def info_constructors_test_suite(name):
env_include_defaults = "1",
launch_target = xcscheme_infos_testable.make_launch_target(),
xcode_configuration = "",
storekit_configuration = "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, and everywhere.

),
)

Expand Down Expand Up @@ -622,6 +623,7 @@ def info_constructors_test_suite(name):
env_include_defaults = "0",
launch_target = xcscheme_infos_testable.make_launch_target("L"),
xcode_configuration = "Run",
storekit_configuration = "",
),

# Expected
Expand Down Expand Up @@ -652,6 +654,7 @@ def info_constructors_test_suite(name):
id = "L",
),
xcode_configuration = "Run",
storekit_configuration = "",
),
)

Expand Down
7 changes: 7 additions & 0 deletions test/internal/xcschemes/infos_from_json_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ def infos_from_json_test_suite(name):
env_include_defaults = "1",
launch_target = full_launch_target,
xcode_configuration = "custom",
storekit_configuration = "",
),
"test": None,
},
Expand Down Expand Up @@ -627,6 +628,7 @@ def infos_from_json_test_suite(name):
env_include_defaults = "1",
launch_target = expected_full_launch_target,
xcode_configuration = "custom",
storekit_configuration = "",
),
),
],
Expand Down Expand Up @@ -682,6 +684,7 @@ def infos_from_json_test_suite(name):
working_directory = "",
),
xcode_configuration = "",
storekit_configuration = "",
),
"test": None,
},
Expand Down Expand Up @@ -782,6 +785,7 @@ def infos_from_json_test_suite(name):
working_directory = "wd",
),
xcode_configuration = "custom",
storekit_configuration = "",
),
"test": None,
},
Expand Down Expand Up @@ -840,6 +844,8 @@ def infos_from_json_test_suite(name):
launch_target = full_launch_target,
use_run_args_and_env = "0",
xcode_configuration = "custom",
run = "",
storekit_configuration = "",
),
"test": None,
},
Expand Down Expand Up @@ -867,6 +873,7 @@ def infos_from_json_test_suite(name):
env_include_defaults = "0",
launch_target = expected_full_launch_target,
xcode_configuration = "custom",
storekit_configuration = "",
),
),
],
Expand Down
1 change: 1 addition & 0 deletions test/internal/xcschemes/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def _dict_to_run_info(d):
env_include_defaults = d["env_include_defaults"],
launch_target = _dict_to_launch_target_info(d["launch_target"]),
xcode_configuration = d["xcode_configuration"],
storekit_configuration = d["storekit_configuration"],
)

def _dict_to_test_info(d):
Expand Down
7 changes: 7 additions & 0 deletions test/internal/xcschemes/write_schemes_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ def write_schemes_test_suite(name):
working_directory = "run working dir",
),
xcode_configuration = "Run",
storekit_configuration = "StorekitConfig",
),
test = xcscheme_infos_testable.make_test(
args = [
Expand Down Expand Up @@ -1112,6 +1113,8 @@ def write_schemes_test_suite(name):
"1",
# - run - xcodeConfiguration
"",
# - run - storekitConfiguration
"",
# - run - launchTarget - isPath
"0",
# - run - launchTarget - id
Expand Down Expand Up @@ -1238,6 +1241,8 @@ def write_schemes_test_suite(name):
"1",
# - run - xcodeConfiguration
"Run",
# - run - storekitConfiguration
"StorekitConfig",
# - run - launchTarget - isPath
"0",
# - run - launchTarget - id
Expand Down Expand Up @@ -1342,6 +1347,8 @@ def write_schemes_test_suite(name):
"1",
# - run - xcodeConfiguration
"",
# - run - storekitConfiguration
"",
# - run - launchTarget - isPath
"1",
# - run - launchTarget - path
Expand Down
18 changes: 18 additions & 0 deletions tools/generators/lib/XCScheme/src/CreateLaunchAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public struct CreateLaunchAction {
enableUBSanitizer: Bool,
enableMainThreadChecker: Bool,
enableThreadPerformanceChecker: Bool,
storeKitConfiguration: String?,
environmentVariables: [EnvironmentVariable],
postActions: [ExecutionAction],
preActions: [ExecutionAction],
Expand All @@ -32,6 +33,7 @@ public struct CreateLaunchAction {
/*enableUBSanitizer:*/ enableUBSanitizer,
/*enableMainThreadChecker:*/ enableMainThreadChecker,
/*enableThreadPerformanceChecker:*/ enableThreadPerformanceChecker,
/*storeKitConfiguration:*/ storeKitConfiguration,
/*environmentVariables:*/ environmentVariables,
/*postActions:*/ postActions,
/*preActions:*/ preActions,
Expand All @@ -52,6 +54,7 @@ extension CreateLaunchAction {
_ enableUBSanitizer: Bool,
_ enableMainThreadChecker: Bool,
_ enableThreadPerformanceChecker: Bool,
_ storeKitConfiguration: String?,
_ environmentVariables: [EnvironmentVariable],
_ postActions: [ExecutionAction],
_ preActions: [ExecutionAction],
Expand All @@ -67,6 +70,7 @@ extension CreateLaunchAction {
enableUBSanitizer: Bool,
enableMainThreadChecker: Bool,
enableThreadPerformanceChecker: Bool,
storeKitConfiguration: String?,
environmentVariables: [EnvironmentVariable],
postActions: [ExecutionAction],
preActions: [ExecutionAction],
Expand Down Expand Up @@ -202,12 +206,26 @@ ignoresPersistentStateOnLaunch = "NO"
runnableString = ""
}

let storeKitConfigurationString: String
if let storeKitConfiguration, storeKitConfiguration.count > 0, storeKitConfiguration != "None" {

storeKitConfigurationString = #"""
<StoreKitConfigurationFileReference
identifier = "\#(storeKitConfiguration)">
</StoreKitConfigurationFileReference>

"""#
} else {
storeKitConfigurationString = ""
}

return #"""
<LaunchAction
\#(components.joined(separator: "\n "))>
\#(preActions.preActionsString)\#
\#(postActions.postActionsString)\#
\#(runnableString)\#
\#(storeKitConfigurationString)\#
\#(commandLineArguments.commandLineArgumentsString)\#
\#(environmentVariables.environmentVariablesString)\#
</LaunchAction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ private func createLaunchActionWithDefaults(
enableUBSanitizer: enableUBSanitizer,
enableMainThreadChecker: enableMainThreadChecker,
enableThreadPerformanceChecker: enableThreadPerformanceChecker,
storeKitConfiguration: nil,
environmentVariables: environmentVariables,
postActions: postActions,
preActions: preActions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ extension Generator.CreateAutomaticSchemeInfo {
enableUBSanitizer: false,
enableMainThreadChecker: false,
enableThreadPerformanceChecker: false,
storeKitConfiguration: nil,
environmentVariables: runEnvironmentVariables,
launchTarget: launchTarget,
xcodeConfiguration: nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,19 @@ extension Generator {
environmentVariables: [TargetID: [EnvironmentVariable]],
executionActionsFile: URL,
extensionHostIDs: [TargetID: [TargetID]],
targetsByID: [TargetID: Target]
targetsByID: [TargetID: Target],
installPath: String,
workspace: String
) async throws -> [SchemeInfo] {
try await callable(
/*commandLineArguments:*/ commandLineArguments,
/*customSchemesFile:*/ customSchemesFile,
/*environmentVariables:*/ environmentVariables,
/*executionActionsFile:*/ executionActionsFile,
/*extensionHostIDs:*/ extensionHostIDs,
/*targetsByID:*/ targetsByID
/*targetsByID:*/ targetsByID,
/*installPath:*/ installPath,
/*workspace:*/ workspace
)
}
}
Expand All @@ -40,13 +44,15 @@ extension Generator {
// MARK: - CreateCustomSchemeInfos.Callable

extension Generator.CreateCustomSchemeInfos {
typealias Callable = (
typealias Callable = (
_ commandLineArguments: [TargetID: [CommandLineArgument]],
_ customSchemesFile: URL,
_ environmentVariables: [TargetID: [EnvironmentVariable]],
_ executionActionsFile: URL,
_ extensionHostIDs: [TargetID: [TargetID]],
_ targetsByID: [TargetID: Target]
_ targetsByID: [TargetID: Target],
_ installPath: String,
_ workspace: String
) async throws -> [SchemeInfo]

static func defaultCallable(
Expand All @@ -55,7 +61,9 @@ extension Generator.CreateCustomSchemeInfos {
environmentVariables: [TargetID: [EnvironmentVariable]],
executionActionsFile: URL,
extensionHostIDs: [TargetID: [TargetID]],
targetsByID: [TargetID: Target]
targetsByID: [TargetID: Target],
installPath: String,
workspace: String
) async throws -> [SchemeInfo] {
let executionActions: [String: [SchemeInfo.ExecutionAction]] =
try await .parse(
Expand Down Expand Up @@ -95,7 +103,9 @@ extension Generator.CreateCustomSchemeInfos {
name: name,
targetCommandLineArguments: commandLineArguments,
targetEnvironmentVariables: environmentVariables,
targetsByID: targetsByID
targetsByID: targetsByID,
installPath: installPath,
workspace: workspace
)

let profile = try rawArgs.consumeArg(
Expand Down Expand Up @@ -453,6 +463,8 @@ set
targetCommandLineArguments: [TargetID: [CommandLineArgument]],
targetEnvironmentVariables: [TargetID: [EnvironmentVariable]],
targetsByID: [TargetID: Target],
installPath: String,
workspace: String,
file: StaticString = #filePath,
line: UInt = #line
) throws -> SchemeInfo.Run {
Expand Down Expand Up @@ -502,6 +514,19 @@ set
let xcodeConfiguration =
try consumeArg("run-xcode-configuration", as: String?.self, in: url)

let storeKitConfiguration = try consumeArg(
"run-storekit-configuration",
as: String?.self,
in: url
)
var storeKitConfigurationWorkspaceRelativePath: String?
if let storeKitConfiguration {
// Provide an example path to xcschemes to relativize against
let installRootURL = URL(filePath: "\(workspace)/\(installPath)/xcshareddata/xcschemes")
let storekitConfigAbsolutePath = URL(filePath: "\(workspace)/\(storeKitConfiguration)")
storeKitConfigurationWorkspaceRelativePath = storekitConfigAbsolutePath.relativize(from: installRootURL)
}

var (
launchTarget,
commandLineArguments,
Expand Down Expand Up @@ -543,6 +568,7 @@ set
enableUBSanitizer: enableUBSanitizer,
enableMainThreadChecker: enableMainThreadChecker,
enableThreadPerformanceChecker: enableThreadPerformanceChecker,
storeKitConfiguration: storeKitConfigurationWorkspaceRelativePath,
environmentVariables: environmentVariables,
launchTarget: launchTarget,
xcodeConfiguration: xcodeConfiguration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ extension Generator.CreateScheme {
enableUBSanitizer: schemeInfo.run.enableUBSanitizer,
enableMainThreadChecker: schemeInfo.run.enableMainThreadChecker,
enableThreadPerformanceChecker: schemeInfo.run.enableThreadPerformanceChecker,
storeKitConfiguration: schemeInfo.run.storeKitConfiguration,
environmentVariables: launchRunnable == nil ?
[] : schemeInfo.run.environmentVariables,
postActions: launchPostActions
Expand Down
4 changes: 3 additions & 1 deletion tools/generators/xcschemes/src/Generator/Generator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ struct Generator {
environmentVariables: environmentVariables,
executionActionsFile: arguments.executionActionsFile,
extensionHostIDs: extensionHostIDs,
targetsByID: targetsByID
targetsByID: targetsByID,
installPath: arguments.installPath,
workspace: arguments.workspace
)

let automaticSchemeInfos = try environment.createAutomaticSchemeInfos(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct SchemeInfo: Equatable {
let enableUBSanitizer: Bool
let enableMainThreadChecker: Bool
let enableThreadPerformanceChecker: Bool
let storeKitConfiguration: String?
let environmentVariables: [EnvironmentVariable]
let launchTarget: LaunchTarget?
let xcodeConfiguration: String?
Expand Down
26 changes: 26 additions & 0 deletions tools/generators/xcschemes/src/Generator/URL+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Foundation
extension URL {
func relativize(from source: URL) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven’t needed this until now. I question if we still need it. Is there a way to make sure it comes in correctly from Starlark instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggled with this a lot. I suppose I could relativize this within starlark and provide a relative path there, but there is no great way to get a true path to the file via the rule itself. The schemes are encoded via json and supplied here: https://github.com/MobileNativeFoundation/rules_xcodeproj/blob/main/xcodeproj/internal/xcodeproj_incremental_rule.bzl#L835

And other things within the scheme match up based on identifier encodings, but this requires a path that is relative to the resultant scheme directory itself in the generated xcodeproj from what I can tell. I am happy to do it differently, but I think the outcome ends up being something considerably more complex. I'm not particularly experienced in working with rules_xcodeproj, so after banging my head on this for a little bit I threw up my hands and went with this. Open to suggestions!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly we want to be able to "cache" things in Bazel. Doing this work in the generator means it's re-done every time the generator runs. I'll leave it up to the other @MobileNativeFoundation/rules_xcodeproj-maintainers on what they think about this.

let sourceComponents = source.deletingLastPathComponent().pathComponents
let destComponents = self.pathComponents

// Find common prefix
var commonPrefixCount = 0
while commonPrefixCount < sourceComponents.count &&
commonPrefixCount < destComponents.count &&
sourceComponents[commonPrefixCount] == destComponents[commonPrefixCount] {
commonPrefixCount += 1
}

// Build relative path
var result = [String]()

// Add "../" for each level to go up
result.append(contentsOf: Array(repeating: "..", count: sourceComponents.count - commonPrefixCount))

// Add remaining destination components
result.append(contentsOf: destComponents[commonPrefixCount...])

return result.joined(separator: "/")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

Loading