From aa3410ff9cf76d090fa3c901afa104d28cfc5f75 Mon Sep 17 00:00:00 2001 From: Alex Deem Date: Wed, 2 Oct 2024 22:56:57 +1000 Subject: [PATCH] Support PBXGroup build file elements eg localized variants (#35) * Add localized file to ExampleProject and associated test * Refactor PBXBuildFile.path(projectFolder:) to leverage guard statements * Refactor PBXBuildFile.path(projectFolder:) to return an array of paths * Support PBXGroup build file elements eg localized variants --- .../DependencyGraph.swift | 52 +++++++++++++------ .../ExampleProject.xcodeproj/project.pbxproj | 17 ++++++ .../ExampleProject/Base.lproj/Example.xib | 10 ++++ .../ExampleProject/en.lproj/Example.strings | 1 + .../SelectiveTestingProjectTests.swift | 16 ++++++ 5 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 Tests/SelectiveTestingTests/ExampleProject/ExampleProject/Base.lproj/Example.xib create mode 100644 Tests/SelectiveTestingTests/ExampleProject/ExampleProject/en.lproj/Example.strings diff --git a/Sources/DependencyCalculator/DependencyGraph.swift b/Sources/DependencyCalculator/DependencyGraph.swift index 27ae829..6ef3a78 100644 --- a/Sources/DependencyCalculator/DependencyGraph.swift +++ b/Sources/DependencyCalculator/DependencyGraph.swift @@ -10,23 +10,41 @@ import Workspace import XcodeProj extension PBXBuildFile { - func path(projectFolder: Path) -> Path? { - if let path = file?.path { - var intermediatePath = Path() + func paths(projectFolder: Path) -> [Path] { + guard let file else { + Logger.warning("PBXBuildFile without file: self=\(self), \n self.product=\(String(describing: product))") + return [] + } + + let paths: [String] = switch file { + case let group as PBXGroup: + group.children.compactMap { $0.path } + default: + if let path = file.path { + [path] + } else { + [] + } + } + + guard paths.count > 0 else { + Logger.warning("File without paths: self=\(self), \n self.file=\(String(describing: file)), \n self.product=\(String(describing: product))") + return [] + } + + var intermediatePath = Path() - var parent = file?.parent + var parent = file.parent - while parent?.path != nil { - if let parentPath = parent?.path { - intermediatePath = Path(parentPath) + intermediatePath - } - parent = parent?.parent + while parent?.path != nil { + if let parentPath = parent?.path { + intermediatePath = Path(parentPath) + intermediatePath } + parent = parent?.parent + } - return projectFolder + intermediatePath + path - } else { - Logger.warning("File without path: self=\(self), \n self.file=\(String(describing: file)), \n self.product=\(String(describing: product))") - return nil + return paths.map { + projectFolder + intermediatePath + $0 } } } @@ -284,13 +302,13 @@ extension WorkspaceInfo { } // Source Files - var filesPaths = try Set(target.sourcesBuildPhase()?.files?.compactMap { file in - file.path(projectFolder: path.parent()) + var filesPaths = try Set(target.sourcesBuildPhase()?.files?.flatMap { file in + file.paths(projectFolder: path.parent()) } ?? []) // Resources - filesPaths = try filesPaths.union(Set(target.resourcesBuildPhase()?.files?.compactMap { file in - file.path(projectFolder: path.parent()) + filesPaths = try filesPaths.union(Set(target.resourcesBuildPhase()?.files?.flatMap { file in + file.paths(projectFolder: path.parent()) } ?? [])) // Establish dependencies based on linked frameworks build phase diff --git a/Tests/SelectiveTestingTests/ExampleProject/ExampleProject.xcodeproj/project.pbxproj b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject.xcodeproj/project.pbxproj index e70196f..ffb4edb 100644 --- a/Tests/SelectiveTestingTests/ExampleProject/ExampleProject.xcodeproj/project.pbxproj +++ b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 27F4680529B145A700A93E94 /* ExampleLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27F4680429B145A700A93E94 /* ExampleLibrary.framework */; }; 27F4680929B145F900A93E94 /* ExampleTargetLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F4680829B145F900A93E94 /* ExampleTargetLibrary.swift */; }; 27F4680C29B1482E00A93E94 /* ExamplePackage in Frameworks */ = {isa = PBXBuildFile; productRef = 27F4680B29B1482E00A93E94 /* ExamplePackage */; }; + B24BBDBD2CAD7228005E6DAC /* Example.xib in Resources */ = {isa = PBXBuildFile; fileRef = B24BBDBC2CAD7228005E6DAC /* Example.xib */; }; FDE924012A5C5AC300D61FD3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE924002A5C5AC300D61FD3 /* ContentView.swift */; }; /* End PBXBuildFile section */ @@ -88,6 +89,8 @@ 27F4680429B145A700A93E94 /* ExampleLibrary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ExampleLibrary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27F4680829B145F900A93E94 /* ExampleTargetLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleTargetLibrary.swift; sourceTree = ""; }; 27F4680A29B1469D00A93E94 /* ExamplePackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ExamplePackage; sourceTree = ""; }; + B24BBDBB2CAD7228005E6DAC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Example.xib; sourceTree = ""; }; + B24BBDBF2CAD7244005E6DAC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Example.strings; sourceTree = ""; }; FDE924002A5C5AC300D61FD3 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -167,6 +170,7 @@ FDE923FE2A5C5AC300D61FD3 /* Deep */, 276DB5C229B144C900E5C615 /* Assets.xcassets */, 276DB5C429B144C900E5C615 /* Preview Content */, + B24BBDBC2CAD7228005E6DAC /* Example.xib */, ); path = ExampleProject; sourceTree = ""; @@ -405,6 +409,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B24BBDBD2CAD7228005E6DAC /* Example.xib in Resources */, 276DB5C629B144C900E5C615 /* Preview Assets.xcassets in Resources */, 276DB5C329B144C900E5C615 /* Assets.xcassets in Resources */, ); @@ -509,6 +514,18 @@ }; /* End PBXTargetDependency section */ +/* Begin PBXVariantGroup section */ + B24BBDBC2CAD7228005E6DAC /* Example.xib */ = { + isa = PBXVariantGroup; + children = ( + B24BBDBB2CAD7228005E6DAC /* Base */, + B24BBDBF2CAD7244005E6DAC /* en */, + ); + name = Example.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 276DB5DD29B144CA00E5C615 /* Debug */ = { isa = XCBuildConfiguration; diff --git a/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/Base.lproj/Example.xib b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/Base.lproj/Example.xib new file mode 100644 index 0000000..a6037d0 --- /dev/null +++ b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/Base.lproj/Example.xib @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/en.lproj/Example.strings b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/en.lproj/Example.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Tests/SelectiveTestingTests/ExampleProject/ExampleProject/en.lproj/Example.strings @@ -0,0 +1 @@ + diff --git a/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift b/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift index 66905f7..47dacf6 100644 --- a/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift +++ b/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift @@ -71,4 +71,20 @@ final class SelectiveTestingProjectTests: XCTestCase { testTool.mainProjectUITests, ])) } + + func testProjectLocalizedPathChange() async throws { + // given + let tool = try testTool.createSUT(config: nil, + basePath: "ExampleProject.xcodeproj") + // when + try testTool.changeFile(at: testTool.projectPath + "ExampleProject/Base.lproj/Example.xib") + + // then + let result = try await tool.run() + XCTAssertEqual(result, Set([ + testTool.mainProjectMainTarget, + testTool.mainProjectTests, + testTool.mainProjectUITests, + ])) + } }