Skip to content

Commit 1029764

Browse files
authored
Merge pull request #78186 from hamishknight/better-infer-project-root
[xcodegen] Infer project root from xcodegen location
2 parents 8f5e37c + dfe1f9c commit 1029764

File tree

4 files changed

+38
-14
lines changed

4 files changed

+38
-14
lines changed

utils/swift-xcodegen/Sources/SwiftXcodeGen/Error.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
enum XcodeGenError: Error, CustomStringConvertible {
1414
case pathNotFound(AbsolutePath)
1515
case noSwiftBuildDir(AbsolutePath, couldBeParent: Bool)
16-
case expectedParent(AbsolutePath)
16+
case couldNotInferProjectRoot(reason: String)
1717

1818
var description: String {
1919
switch self {
@@ -23,8 +23,11 @@ enum XcodeGenError: Error, CustomStringConvertible {
2323
let base = "no swift build directory found in '\(basePath)'"
2424
let note = "; did you mean to pass the path of the parent?"
2525
return couldBeParent ? "\(base)\(note)" : base
26-
case .expectedParent(let basePath):
27-
return "expected '\(basePath)' to have parent directory"
26+
case .couldNotInferProjectRoot(let reason):
27+
return """
28+
could not infer project root path; \(reason); please manually specify \
29+
using '--project-root-dir' instead
30+
"""
2831
}
2932
}
3033
}

utils/swift-xcodegen/Sources/SwiftXcodeGen/Ninja/NinjaBuildDir.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,20 @@ public final class NinjaBuildDir: Sendable {
3030
let couldBeParent = buildDir.fileName.hasPrefix("swift-")
3131
throw XcodeGenError.noSwiftBuildDir(buildDir, couldBeParent: couldBeParent)
3232
}
33-
34-
private static func detectProjectRoot(
35-
buildDir: AbsolutePath
36-
) throws -> AbsolutePath {
37-
guard let parent = buildDir.parentDir else {
38-
throw XcodeGenError.expectedParent(buildDir)
39-
}
40-
guard let projectDir = parent.parentDir else {
41-
throw XcodeGenError.expectedParent(parent)
33+
34+
// We can infer the project root from the location of swift-xcodegen itself.
35+
// 1 2 3 4 5 6 7
36+
// #filePath = <root>/swift/utils/swift-xcodegen/Sources/SwiftXcodeGen/Ninja/NinjaBuildDir.swift
37+
private static let inferredProjectRootPath = AbsolutePath(#filePath).dropLast(7)
38+
39+
private static func detectProjectRoot() throws -> AbsolutePath {
40+
let inferredSwiftPath = inferredProjectRootPath.appending(Repo.swift.relativePath)
41+
guard inferredSwiftPath.exists else {
42+
throw XcodeGenError.couldNotInferProjectRoot(
43+
reason: "expected swift repo at '\(inferredSwiftPath)'"
44+
)
4245
}
43-
return projectDir
46+
return inferredProjectRootPath
4447
}
4548

4649
public init(at path: AbsolutePath, projectRootDir: AbsolutePath?) throws {
@@ -49,7 +52,7 @@ public final class NinjaBuildDir: Sendable {
4952
}
5053
self.path = path
5154
self.tripleSuffix = try Self.detectTripleSuffix(buildDir: path)
52-
self.projectRootDir = try projectRootDir ?? Self.detectProjectRoot(buildDir: path)
55+
self.projectRootDir = try projectRootDir ?? Self.detectProjectRoot()
5356
}
5457

5558
public func buildDir(for repo: Repo) throws -> RepoBuildDir {

utils/swift-xcodegen/Sources/SwiftXcodeGen/Path/PathProtocol.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public extension PathProtocol {
2828
return Self(result)
2929
}
3030

31+
/// Drops the last `n` components, or all components if `n` is greater
32+
/// than the number of components.
33+
func dropLast(_ n: Int = 1) -> Self {
34+
Self(FilePath(root: storage.root, storage.components.dropLast(n)))
35+
}
36+
3137
var fileName: String {
3238
storage.lastComponent?.string ?? ""
3339
}

utils/swift-xcodegen/Tests/SwiftXcodeGenTest/PathTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,16 @@ class PathTests: XCTestCase {
2525
XCTAssertEqual(AbsolutePath("/foo").parentDir, "/")
2626
XCTAssertEqual(AbsolutePath("/foo/bar").parentDir, "/foo")
2727
}
28+
29+
func testDropLast() throws {
30+
XCTAssertEqual(AbsolutePath("/").dropLast(), "/")
31+
XCTAssertEqual(AbsolutePath("/foo/bar").dropLast(), "/foo")
32+
XCTAssertEqual(AbsolutePath("/foo/bar").dropLast(2), "/")
33+
XCTAssertEqual(AbsolutePath("/foo/bar").dropLast(5), "/")
34+
35+
XCTAssertEqual(RelativePath("").dropLast(), "")
36+
XCTAssertEqual(RelativePath("foo/bar").dropLast(), "foo")
37+
XCTAssertEqual(RelativePath("foo/bar").dropLast(2), "")
38+
XCTAssertEqual(RelativePath("foo/bar").dropLast(5), "")
39+
}
2840
}

0 commit comments

Comments
 (0)