mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Add a tool to build MatrixRustSDK. (#369)
This commit is contained in:
+12
-2
@@ -18,7 +18,17 @@ The Xcode project itself is generated through [xcodegen](https://github.com/yona
|
|||||||
|
|
||||||
Dependencies will be automatically fetched through the Swift Package Manager, including a release version of the MatrixRustSDK. If you encounter issues while resolving the package graph please attempt a cache reset through `File -> Packages -> Reset Package Caches`.
|
Dependencies will be automatically fetched through the Swift Package Manager, including a release version of the MatrixRustSDK. If you encounter issues while resolving the package graph please attempt a cache reset through `File -> Packages -> Reset Package Caches`.
|
||||||
|
|
||||||
For instructions on how to setup the RustSDK in development mode please refer to the [matrix-rust-components-swift](https://github.com/matrix-org/matrix-rust-components-swift) repository.
|
To setup the RustSDK in local development mode run the following command
|
||||||
|
|
||||||
|
```
|
||||||
|
swift run tools build-sdk
|
||||||
|
```
|
||||||
|
|
||||||
|
This will clone a copy of the SDK if needed, build it for all supported architectures and configure ElementX to use the built framework. To learn about additional options run
|
||||||
|
|
||||||
|
```
|
||||||
|
swift run tools build-sdk --help
|
||||||
|
```
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
@@ -109,7 +119,7 @@ $ towncrier build --draft --version 1.2.3
|
|||||||
For Swift coding style we use [SwiftLint](https://github.com/realm/SwiftLint) to check some conventions at compile time (rules are located in the `.swiftlint.yml` file).
|
For Swift coding style we use [SwiftLint](https://github.com/realm/SwiftLint) to check some conventions at compile time (rules are located in the `.swiftlint.yml` file).
|
||||||
Otherwise please have a look to [Apple Swift conventions](https://swift.org/documentation/api-design-guidelines.html#conventions). We are also using some of the conventions of [raywenderlich.com Swift style guide](https://github.com/raywenderlich/swift-style-guide).
|
Otherwise please have a look to [Apple Swift conventions](https://swift.org/documentation/api-design-guidelines.html#conventions). We are also using some of the conventions of [raywenderlich.com Swift style guide](https://github.com/raywenderlich/swift-style-guide).
|
||||||
|
|
||||||
We enforce the coding style by running checks on the CI for every PR through [Danger](Dangerfile.swift), [SwiftLint](.swiftlint.yml) and [SonarCloud](https://sonarcloud.io/project/overview?id=vector-im_element-x-ios)
|
We enforce the coding style by running checks on the CI for every PR through [Danger](Dangerfile.swift), [SwiftLint](.swiftlint.yml), [SwiftFormat](.swiftformat) and [SonarCloud](https://sonarcloud.io/project/overview?id=vector-im_element-x-ios)
|
||||||
|
|
||||||
We also gather coverage reports on every PR through [Codecov](https://app.codecov.io/gh/vector-im/element-x-ios) and will eventually start enforcing minimums.
|
We also gather coverage reports on every PR through [Codecov](https://app.codecov.io/gh/vector-im/element-x-ios) and will eventually start enforcing minimums.
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,15 @@
|
|||||||
"version" : "7.30.2"
|
"version" : "7.30.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-argument-parser",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-argument-parser",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
|
||||||
|
"version" : "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swift-snapshot-testing",
|
"identity" : "swift-snapshot-testing",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@@ -143,6 +152,15 @@
|
|||||||
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
|
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
|
||||||
"version" : "1.9.6"
|
"version" : "1.9.6"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "yams",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/jpsim/Yams",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "01835dc202670b5bb90d07f3eae41867e9ed29f6",
|
||||||
|
"version" : "5.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version" : 2
|
"version" : 2
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
"version" : "0.0.3"
|
"version" : "0.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-argument-parser",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-argument-parser",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
|
||||||
|
"version" : "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swiftui-introspect",
|
"identity" : "swiftui-introspect",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@@ -17,6 +26,15 @@
|
|||||||
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
|
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
|
||||||
"version" : "0.1.4"
|
"version" : "0.1.4"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "yams",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/jpsim/Yams.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "01835dc202670b5bb90d07f3eae41867e9ed29f6",
|
||||||
|
"version" : "5.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version" : 2
|
"version" : 2
|
||||||
|
|||||||
+19
-6
@@ -1,17 +1,24 @@
|
|||||||
// swift-tools-version: 5.6
|
// swift-tools-version: 5.7
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "DesignKit",
|
name: "Element Swift",
|
||||||
platforms: [.iOS(.v14)],
|
platforms: [
|
||||||
|
.iOS(.v14),
|
||||||
|
.macOS(.v13)
|
||||||
|
],
|
||||||
products: [
|
products: [
|
||||||
.library(name: "DesignKit", targets: ["DesignKit"])
|
.library(name: "DesignKit", targets: ["DesignKit"]),
|
||||||
|
.executable(name: "tools", targets: ["Tools"])
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/vector-im/element-design-tokens.git", exact: "0.0.3"),
|
.package(url: "https://github.com/vector-im/element-design-tokens.git", exact: "0.0.3"),
|
||||||
.package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.4")
|
.package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.4"),
|
||||||
|
/* Command line tools dependencies */
|
||||||
|
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.0"),
|
||||||
|
.package(url: "https://github.com/jpsim/Yams", from: "5.0.1")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(name: "DesignKit",
|
.target(name: "DesignKit",
|
||||||
@@ -22,6 +29,12 @@ let package = Package(
|
|||||||
path: "DesignKit"),
|
path: "DesignKit"),
|
||||||
.testTarget(name: "DesignKitTests",
|
.testTarget(name: "DesignKitTests",
|
||||||
dependencies: ["DesignKit"],
|
dependencies: ["DesignKit"],
|
||||||
path: "DesignKitTests")
|
path: "DesignKitTests"),
|
||||||
|
.executableTarget(name: "Tools",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
|
.product(name: "Yams", package: "Yams")
|
||||||
|
],
|
||||||
|
path: "Tools/Sources")
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import ArgumentParser
|
||||||
|
import Foundation
|
||||||
|
import Yams
|
||||||
|
|
||||||
|
struct BuildSDK: ParsableCommand {
|
||||||
|
static var configuration = CommandConfiguration(abstract: "A tool to checkout and build MatrixRustSDK locally for development.")
|
||||||
|
|
||||||
|
@Argument(help: "An optional argument to specify a branch of the SDK.")
|
||||||
|
var branch: String?
|
||||||
|
|
||||||
|
@Option(help: "The target to build for such as aarch64-apple-ios. Omit this option to build for all targets.")
|
||||||
|
var target: String?
|
||||||
|
|
||||||
|
private var projectDirectoryURL: URL { URL(filePath: FileManager.default.currentDirectoryPath) }
|
||||||
|
private var parentDirectoryURL: URL { projectDirectoryURL.deletingLastPathComponent() }
|
||||||
|
private var sdkDirectoryURL: URL { parentDirectoryURL.appending(path: "matrix-rust-sdk") }
|
||||||
|
|
||||||
|
enum Error: LocalizedError {
|
||||||
|
case scriptFailed
|
||||||
|
case rustupOutputFailure
|
||||||
|
case missingRustTargets([String])
|
||||||
|
case failureParsingProjectYAML
|
||||||
|
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .missingRustTargets(let missingTargets):
|
||||||
|
return """
|
||||||
|
Rust is missing the necessary targets to build the SDK.
|
||||||
|
Run the following command to install them:
|
||||||
|
|
||||||
|
rustup target add \(missingTargets.joined(separator: " ")) --toolchain nightly
|
||||||
|
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() throws {
|
||||||
|
try checkRustupTargets()
|
||||||
|
try cloneSDKIfNeeded()
|
||||||
|
try checkoutBranchIfSupplied()
|
||||||
|
try buildFramework()
|
||||||
|
try updateXcodeProject()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that all of the required targets have been added through rustup
|
||||||
|
/// but only when the ``target`` option hasn't been supplied.
|
||||||
|
func checkRustupTargets() throws {
|
||||||
|
guard target == nil else { return }
|
||||||
|
guard let output = try zsh("rustup show", workingDirectoryURL: projectDirectoryURL) else { throw Error.rustupOutputFailure }
|
||||||
|
|
||||||
|
var requiredTargets = [
|
||||||
|
"aarch64-apple-darwin": false,
|
||||||
|
"aarch64-apple-ios": false,
|
||||||
|
"aarch64-apple-ios-sim": false,
|
||||||
|
"x86_64-apple-darwin": false,
|
||||||
|
"x86_64-apple-ios": false
|
||||||
|
]
|
||||||
|
output.enumerateLines { line, _ in
|
||||||
|
if requiredTargets.keys.contains(line) {
|
||||||
|
requiredTargets[line] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let missingTargets = requiredTargets.compactMap { !$0.value ? $0.key : nil }
|
||||||
|
guard missingTargets.isEmpty else { throw Error.missingRustTargets(missingTargets) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clones the Rust SDK if a copy isn't found in the parent directory.
|
||||||
|
func cloneSDKIfNeeded() throws {
|
||||||
|
guard !FileManager.default.fileExists(atPath: sdkDirectoryURL.path) else { return }
|
||||||
|
try zsh("git clone https://github.com/matrix-org/matrix-rust-sdk", workingDirectoryURL: parentDirectoryURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checkout the specified branch of the SDK if supplied.
|
||||||
|
func checkoutBranchIfSupplied() throws {
|
||||||
|
guard let branch else { return }
|
||||||
|
try zsh("git checkout \(branch)", workingDirectoryURL: sdkDirectoryURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the Rust SDK as an XCFramework with the debug profile.
|
||||||
|
func buildFramework() throws {
|
||||||
|
var buildCommand = "cargo xtask swift build-framework --profile dbg"
|
||||||
|
if let target {
|
||||||
|
buildCommand.append(" --only-target \(target)")
|
||||||
|
}
|
||||||
|
try zsh(buildCommand, workingDirectoryURL: sdkDirectoryURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the Xcode project to use the build of the SDK.
|
||||||
|
func updateXcodeProject() throws {
|
||||||
|
try updateProjectYAML()
|
||||||
|
try zsh("xcodegen", workingDirectoryURL: projectDirectoryURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update project.yml with the local path of the SDK.
|
||||||
|
func updateProjectYAML() throws {
|
||||||
|
let yamlURL = projectDirectoryURL.appending(path: "project.yml")
|
||||||
|
let yamlString = try String(contentsOf: yamlURL)
|
||||||
|
guard var projectConfig = try Yams.compose(yaml: yamlString) else { throw Error.failureParsingProjectYAML }
|
||||||
|
|
||||||
|
projectConfig["packages"]?.mapping?["MatrixRustSDK"]? = ["path": "../matrix-rust-sdk"]
|
||||||
|
|
||||||
|
let updatedYAMLString = try Yams.serialize(node: projectConfig)
|
||||||
|
try updatedYAMLString.write(to: yamlURL, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a command in zsh.
|
||||||
|
@discardableResult
|
||||||
|
func zsh(_ command: String, workingDirectoryURL: URL) throws -> String? {
|
||||||
|
let process = Process()
|
||||||
|
process.executableURL = URL(filePath: "/bin/zsh")
|
||||||
|
process.arguments = ["-c", command]
|
||||||
|
process.currentDirectoryURL = workingDirectoryURL
|
||||||
|
|
||||||
|
let outputPipe = Pipe()
|
||||||
|
process.standardOutput = outputPipe
|
||||||
|
|
||||||
|
try process.run()
|
||||||
|
process.waitUntilExit()
|
||||||
|
|
||||||
|
guard process.terminationReason == .exit, process.terminationStatus == 0 else { throw Error.scriptFailed }
|
||||||
|
|
||||||
|
guard let outputData = try outputPipe.fileHandleForReading.readToEnd() else { return nil }
|
||||||
|
return String(data: outputData, encoding: .utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import ArgumentParser
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Tools: ParsableCommand {
|
||||||
|
static var configuration = CommandConfiguration(abstract: "A collection of command line tools for ElementX",
|
||||||
|
subcommands: [BuildSDK.self])
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Tools: Add a command line tool to build a local copy of the SDK for debugging.
|
||||||
Reference in New Issue
Block a user