Skip to content
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

Add selected_model_versions generator #2304

Merged
merged 1 commit into from
Jun 28, 2023
Merged
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
1 change: 1 addition & 0 deletions tools/generators/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ filegroup(
"//" + package_name() + "/legacy:release_files",
# TODO: Uncomment when we start using the incremental generator
# "//" + package_name() + "/pbxproj_prefix:release_files",
# "//" + package_name() + "/selected_model_versions:release_files",
],
tags = ["manual"],
visibility = ["//:__subpackages__"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ extension ElementCreator {
private let createFile: CreateFile
private let createIdentifier: CreateIdentifier
private let createVersionGroupElement: CreateVersionGroupElement
private let selectedModelVersions: [BazelPath: BazelPath]
private let selectedModelVersions: [BazelPath: String]

private let callable: Callable

/// - Parameters:
/// - selectedModelVersions: A `Dictionary` that maps the `BazelPath`
/// for an `.xcdatamodeld` group to its selected `.xcdatamodel`
/// file.
/// file name.
/// - callable: The function that will be called in
/// `callAsFunction()`.
init(
createFile: CreateFile,
createIdentifier: CreateIdentifier,
createVersionGroupElement: CreateVersionGroupElement,
selectedModelVersions: [BazelPath: BazelPath],
selectedModelVersions: [BazelPath: String],
callable: @escaping Callable
) {
self.createFile = createFile
Expand Down Expand Up @@ -58,7 +58,7 @@ extension ElementCreator.CreateVersionGroup {
_ createFile: ElementCreator.CreateFile,
_ createIdentifier: ElementCreator.CreateIdentifier,
_ createVersionGroupElement: ElementCreator.CreateVersionGroupElement,
_ selectedModelVersions: [BazelPath: BazelPath]
_ selectedModelVersions: [BazelPath: String]
) -> GroupChild.ElementAndChildren

static func defaultCallable(
Expand All @@ -68,7 +68,7 @@ extension ElementCreator.CreateVersionGroup {
createFile: ElementCreator.CreateFile,
createIdentifier: ElementCreator.CreateIdentifier,
createVersionGroupElement: ElementCreator.CreateVersionGroupElement,
selectedModelVersions: [BazelPath: BazelPath]
selectedModelVersions: [BazelPath: String]
) -> GroupChild.ElementAndChildren {
let bazelPath = parentBazelPath + node
let name = node.name
Expand All @@ -82,16 +82,15 @@ extension ElementCreator.CreateVersionGroup {
var children: [GroupChild.ElementAndChildren] = []
var selectedChildIdentifier: String? = nil
for node in node.children {
let childBazelPath = bazelPath + node
let result = createFile(
for: node,
bazelPath: childBazelPath,
bazelPath: bazelPath + node,
specialRootGroupType: specialRootGroupType,
identifierForBazelPaths: identifier
)
children.append(result)

if childBazelPath == selectedModelVersion {
if node.name == selectedModelVersion {
selectedChildIdentifier = result.element.identifier
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Path to a file that contains the absolute path to the Bazel execution root.
@Argument(
help: """
Path to a file that contains a JSON representation of \
`[BazelPath: BazelPath]`, mapping `.xcdatamodeld` file paths to selected \
`.xcdatamodel` file paths.
`[BazelPath: String]`, mapping `.xcdatamodeld` file paths to selected \
`.xcdatamodel` file names.
""",
transform: { URL(fileURLWithPath: $0, isDirectory: false) }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ extension ElementCreator.Environment {
func createCreateRootElements(
executionRoot: String,
externalDir: String,
selectedModelVersions: [BazelPath: BazelPath],
selectedModelVersions: [BazelPath: String],
workspace: String
) -> ElementCreator.CreateRootElements {
let createAttributes = ElementCreator.CreateAttributes(
Expand All @@ -89,7 +89,7 @@ extension ElementCreator.Environment {
resolveSymlink: resolveSymlink,
callable: createAttributesCallable
)

let createFileElement = ElementCreator.CreateFileElement(
createAttributes: createAttributes,
createIdentifier: createIdentifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ extension ElementCreator {
}

/// Reads the file at `url`, returning a mapping of `.xcdatamodeld`
/// file paths to selected `.xcdatamodel` file files.
func callAsFunction(_ url: URL) throws -> [BazelPath: BazelPath] {
/// file paths to selected `.xcdatamodel` file names.
func callAsFunction(_ url: URL) throws -> [BazelPath: String] {
return try callable(url)
}
}
Expand All @@ -26,12 +26,12 @@ extension ElementCreator {
// MARK: - ReadSelectedModelVersionsFile.Callable

extension ElementCreator.ReadSelectedModelVersionsFile {
typealias Callable = (_ url: URL) throws -> [BazelPath: BazelPath]
typealias Callable = (_ url: URL) throws -> [BazelPath: String]

static func defaultCallable(_ url: URL) throws -> [BazelPath: BazelPath] {
static func defaultCallable(_ url: URL) throws -> [BazelPath: String] {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
return try decoder
.decode([BazelPath: BazelPath].self, from: Data(contentsOf: url))
.decode([BazelPath: String].self, from: Data(contentsOf: url))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ final class CreateVersionGroupTests: XCTestCase {

let expectedBazelPath: BazelPath = "bazel/path/node.xcdatamodeld"

let selectedModelVersions: [BazelPath: BazelPath] = [
"another/a.xcdatamodeld": "b.xcdatamodel",
expectedBazelPath: "bazel/path/node.xcdatamodeld/b.xcdatamodel",
let selectedModelVersions: [BazelPath: String] = [
"another/a.xcdatamodeld": "other.xcdatamodel",
expectedBazelPath: "b.xcdatamodel",
]

let expectedCreateIdentifierCalled: [
Expand Down
31 changes: 31 additions & 0 deletions tools/generators/selected_model_versions/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
py_library(
name = "selected_model_versions_library",
srcs = ["selected_model_versions.py"],
srcs_version = "PY3",
# TODO: Restrict visibility
visibility = ["//visibility:public"],
)

py_binary(
name = "selected_model_versions",
srcs = ["selected_model_versions.py"],
python_version = "PY3",
srcs_version = "PY3",
# TODO: Restrict visibility
visibility = ["//visibility:public"],
deps = [":selected_model_versions_library"],
)

# Release

filegroup(
name = "release_files",
srcs = glob(
["**"],
exclude = [
"**/.*",
],
),
tags = ["manual"],
visibility = ["//:__subpackages__"],
)
6 changes: 6 additions & 0 deletions tools/generators/selected_model_versions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# `selected_model_versions` file generator

The `selected_model_versions` generator creates a file that contains a JSON
representation of `[BazelPath: String]`, mapping `.xcdatamodeld` file paths to
selected `.xcdatamodel` file names. The output file is used by the
[`files_and_groups`](../files_and_groups/README.md) generator.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/python3

import os
import plistlib
import sys


def _main(output_path: str, xcurrentversions_file_list: str) -> None:
with open(xcurrentversions_file_list, encoding = "utf-8") as fp:
paths = fp.read().splitlines()

results = []
for path in paths:
with open(path, 'rb') as fp:
plist = plistlib.load(fp)

version = plist.get("_XCCurrentVersionName")
if not version:
print(
f"WARNING: `_XCCurrentVersionName` key not found in {path}",
file = sys.stderr,
)
continue

container = os.path.dirname(path)

results.append(f'"{container}"')
results.append(f'"{version}"')

with open(output_path, encoding = "utf-8", mode = "w") as fp:
fp.write(f'[{",".join(results)}]\n')


if __name__ == "__main__":
if len(sys.argv) != 3:
print(
f"""\
Usage: {sys.argv[0]} <output_file> <path/to/xcurrentversions_file_list>
""",
file = sys.stderr,
)
exit(1)

_main(sys.argv[1], sys.argv[2])
43 changes: 43 additions & 0 deletions xcodeproj/internal/selected_model_versions.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Functions generating the `selected_model_versions` file."""

def write_selected_model_versions_file(
*,
actions,
name,
tool,
xccurrentversions_files):
"""
Creates a `File` that contains a JSON representation of \
`[BazelPath: String]`, mapping `.xcdatamodeld` file paths to selected \
`.xcdatamodel` file names.

Args:
actions: `ctx.actions`.
name: The name of the target creating the file.
tool: The executable to run to generate the file.
xccurrentversions_files: A `list` of `File`s containing the
`xccurrentversion` files to read.

Returns:
The generated `File`.
"""
output = actions.declare_file("{}_selected_model_versions".format(name))

args = actions.args()
args.add(output)

files_args = actions.args()
files_args.use_param_file("%s", use_always = True)
files_args.set_param_file_format("multiline")

files_args.add_all(xccurrentversions_files)

actions.run(
arguments = [args, files_args],
executable = tool,
inputs = xccurrentversions_files,
outputs = [output],
mnemonic = "WriteSelectedModelVersionsFile",
)

return output