From 2f2c89e0c177cb24b6daf32ecccfaa05d6be7fd5 Mon Sep 17 00:00:00 2001 From: ryohey Date: Mon, 25 Sep 2017 22:24:32 +0900 Subject: [PATCH 1/4] fix localisation variant groups --- Sources/XcodeGenKit/PBXProjGenerator.swift | 81 +++++++++++++++++----- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index b303b759f..a990fd3ee 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -22,6 +22,7 @@ public class PBXProjGenerator { var fileReferencesByPath: [Path: String] = [:] var groupsByPath: [Path: PBXGroup] = [:] + var variantGroupsByPath: [Path: PBXVariantGroup] = [:] var targetNativeReferences: [String: String] = [:] var targetBuildFileReferences: [String: String] = [:] @@ -151,7 +152,6 @@ public class PBXProjGenerator { settings = ["ATTRIBUTES": ["Public"]] } let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference), fileRef: fileReference, settings: settings) - addObject(buildFile) return SourceFile(path: path, fileReference: fileReference, buildFile: buildFile) } @@ -160,11 +160,11 @@ public class PBXProjGenerator { let carthageDependencies = getAllCarthageDependencies(target: target) let sourcePaths = target.sources.map { basePath + $0 } - var sourceFilePaths: [Path] = [] + var sourceFiles: [SourceFile] = [] for source in sourcePaths { let sourceGroups = try getGroups(path: source) - sourceFilePaths += sourceGroups.filePaths + sourceFiles += sourceGroups.sourceFiles } // find all Info.plist @@ -310,7 +310,8 @@ public class PBXProjGenerator { var buildPhases: [String] = [] func getBuildFilesForPhase(_ buildPhase: BuildPhase) -> [String] { - let files = sourceFilePaths.filter { getBuildPhaseForPath($0) == buildPhase }.map(generateSourceFile) + let files = sourceFiles.filter { getBuildPhaseForPath($0.path) == buildPhase } + files.forEach { addObject($0.buildFile) } return files.map { $0.buildFile.reference } } @@ -467,7 +468,7 @@ public class PBXProjGenerator { } } - func getGroups(path: Path, depth: Int = 0) throws -> (filePaths: [Path], groups: [PBXGroup]) { + func getGroups(path: Path, depth: Int = 0) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) { let excludedFiles: [String] = [".DS_Store"] @@ -484,34 +485,76 @@ public class PBXProjGenerator { .filter { $0.extension == "lproj" } .sorted { $0.lastComponent < $1.lastComponent } - var groupChildren: [String] = [] - var allFilePaths: [Path] = filePaths + var groupChildren: [String] = filePaths.map { getFileReference(path: $0, inPath: path) } + var allSourceFiles: [SourceFile] = filePaths.map { generateSourceFile(path: $0) } var groups: [PBXGroup] = [] for path in directories { let subGroups = try getGroups(path: path, depth: depth + 1) - allFilePaths += subGroups.filePaths + allSourceFiles += subGroups.sourceFiles groupChildren.append(subGroups.groups.first!.reference) groups += subGroups.groups } - for filePath in filePaths { - let fileReference = getFileReference(path: filePath, inPath: path) - groupChildren.append(fileReference) + // create variant groups of the base localisation first + var baseLocalisationVariantGroups:[PBXVariantGroup] = [] + if let baseLocalisedDirectory = localisedDirectories.first(where: { $0.lastComponent == "Base.lproj" }) { + for path in try baseLocalisedDirectory.children() { + let filePath = "\(baseLocalisedDirectory.lastComponent)/\(path.lastComponent)" + + let variantGroup: PBXVariantGroup + if let cachedGroup = variantGroupsByPath[path] { + variantGroup = cachedGroup + } else { + variantGroup = PBXVariantGroup(reference: generateUUID(PBXVariantGroup.self, filePath), + children: [], + name: path.lastComponent, + sourceTree: .group) + variantGroupsByPath[path] = variantGroup + + addObject(variantGroup) + groupChildren.append(variantGroup.reference) + } + + baseLocalisationVariantGroups.append(variantGroup) + + let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, variantGroup.reference), fileRef: variantGroup.reference, settings: nil) + allSourceFiles.append(SourceFile(path: path, fileReference: variantGroup.reference, buildFile: buildFile)) + } } + // add references to localised resources into base localisation variant groups for localisedDirectory in localisedDirectories { + let localisationName = localisedDirectory.lastComponentWithoutExtension for path in try localisedDirectory.children().sorted { $0.lastComponent < $1.lastComponent } { + guard fileReferencesByPath[path] == nil else { + continue + } + let filePath = "\(localisedDirectory.lastComponent)/\(path.lastComponent)" - let fileReference = PBXFileReference(reference: generateUUID(PBXFileReference.self, localisedDirectory.lastComponent), sourceTree: .group, name: localisedDirectory.lastComponentWithoutExtension, path: filePath) - addObject(fileReference) - let variantGroup = PBXVariantGroup(reference: generateUUID(PBXVariantGroup.self, path.lastComponent), children: [fileReference.reference], name: path.lastComponent, sourceTree: .group) - addObject(variantGroup) + // find base localisation variant group + let name = path.lastComponentWithoutExtension + let variantGroup = baseLocalisationVariantGroups.first(where: { Path($0.name).lastComponentWithoutExtension == name }) + + let reference = PBXFileReference(reference: generateUUID(PBXFileReference.self, path.lastComponent), + sourceTree: .group, + name: variantGroup != nil ? localisationName : path.lastComponent, + path: filePath) + addObject(reference) + fileReferencesByPath[path] = reference.reference + let fileReference = reference.reference - fileReferencesByPath[path] = variantGroup.reference - groupChildren.append(variantGroup.reference) - allFilePaths.append(path) + if let variantGroup = variantGroup { + variantGroup.children.append(fileReference) + } else { + // add SourceFile to group if there is no Base.lproj directory + let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference), + fileRef: fileReference, + settings: nil) + allSourceFiles.append(SourceFile(path: path, fileReference: fileReference, buildFile: buildFile)) + groupChildren.append(fileReference) + } } } @@ -528,6 +571,6 @@ public class PBXProjGenerator { groupsByPath[path] = group } groups.insert(group, at: 0) - return (allFilePaths, groups) + return (allSourceFiles, groups) } } From bc9c007c539900073b908a0c38c05c4da21d4767 Mon Sep 17 00:00:00 2001 From: ryohey Date: Wed, 27 Sep 2017 17:25:33 +0900 Subject: [PATCH 2/4] add test for variant groups --- .../Base.lproj/LocalizedStoryboard.storyboard | 7 ++++ .../en.lproj/LocalizedStoryboard.strings | 1 + Tests/XcodeGenKitTests/FixtureTests.swift | 38 ++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 Fixtures/TestProject/TestProject/Base.lproj/LocalizedStoryboard.storyboard create mode 100644 Fixtures/TestProject/TestProject/en.lproj/LocalizedStoryboard.strings diff --git a/Fixtures/TestProject/TestProject/Base.lproj/LocalizedStoryboard.storyboard b/Fixtures/TestProject/TestProject/Base.lproj/LocalizedStoryboard.storyboard new file mode 100644 index 000000000..f9a048edf --- /dev/null +++ b/Fixtures/TestProject/TestProject/Base.lproj/LocalizedStoryboard.storyboard @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Fixtures/TestProject/TestProject/en.lproj/LocalizedStoryboard.strings b/Fixtures/TestProject/TestProject/en.lproj/LocalizedStoryboard.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Fixtures/TestProject/TestProject/en.lproj/LocalizedStoryboard.strings @@ -0,0 +1 @@ + diff --git a/Tests/XcodeGenKitTests/FixtureTests.swift b/Tests/XcodeGenKitTests/FixtureTests.swift index 644319afe..8fad85429 100644 --- a/Tests/XcodeGenKitTests/FixtureTests.swift +++ b/Tests/XcodeGenKitTests/FixtureTests.swift @@ -6,7 +6,7 @@ import ProjectSpec let fixturePath = Path(#file).parent().parent().parent() + "Fixtures" -func generate(specPath: Path, projectPath: Path) throws { +func generate(specPath: Path, projectPath: Path) throws -> XcodeProj { let spec = try ProjectSpec(path: specPath) let generator = ProjectGenerator(spec: spec, path: specPath.parent()) let project = try generator.generateProject() @@ -17,13 +17,47 @@ func generate(specPath: Path, projectPath: Path) throws { if newProject != oldProject { throw failure("\(projectPath.string) has changed. If change is legitimate commit the change and run test again") } + + return newProject } func fixtureTests() { describe("Test Project") { + var project: XcodeProj? + $0.it("generates") { - try generate(specPath: fixturePath + "TestProject/spec.yml", projectPath: fixturePath + "TestProject/GeneratedProject.xcodeproj") + project = try generate(specPath: fixturePath + "TestProject/spec.yml", projectPath: fixturePath + "TestProject/GeneratedProject.xcodeproj") + } + + $0.it("generates variant group") { + guard let project = project else { throw failure("Project is not generated") } + + func getFileReferences(_ path: String) -> [PBXFileReference] { + return project.pbxproj.fileReferences.filter { $0.path == path } + } + + func getVariableGroups(_ name: String?) -> [PBXVariantGroup] { + return project.pbxproj.variantGroups.filter { $0.name == name } + } + + let resourceName = "LocalizedStoryboard.storyboard" + let baseResource = "Base.lproj/LocalizedStoryboard.storyboard" + let localizedResource = "en.lproj/LocalizedStoryboard.strings" + + guard let variableGroup = getVariableGroups(resourceName).first else { throw failure("Couldn't find the variable group") } + + do { + let refs = getFileReferences(baseResource) + try expect(refs.count) == 1 + try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1 + } + + do { + let refs = getFileReferences(localizedResource) + try expect(refs.count) == 1 + try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1 + } } } } From 859609158cbbe94930962c9c13848e3e7e46232c Mon Sep 17 00:00:00 2001 From: ryohey Date: Mon, 16 Oct 2017 11:49:52 +0900 Subject: [PATCH 3/4] fix localized sources --- Sources/XcodeGenKit/PBXProjGenerator.swift | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index a990fd3ee..c42defbb3 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -527,23 +527,26 @@ public class PBXProjGenerator { for localisedDirectory in localisedDirectories { let localisationName = localisedDirectory.lastComponentWithoutExtension for path in try localisedDirectory.children().sorted { $0.lastComponent < $1.lastComponent } { - guard fileReferencesByPath[path] == nil else { - continue - } + let filePath = "\(localisedDirectory.lastComponent)/\(path.lastComponent)" // find base localisation variant group let name = path.lastComponentWithoutExtension - let variantGroup = baseLocalisationVariantGroups.first(where: { Path($0.name).lastComponentWithoutExtension == name }) - - let reference = PBXFileReference(reference: generateUUID(PBXFileReference.self, path.lastComponent), - sourceTree: .group, - name: variantGroup != nil ? localisationName : path.lastComponent, - path: filePath) - addObject(reference) - fileReferencesByPath[path] = reference.reference - let fileReference = reference.reference + let variantGroup = baseLocalisationVariantGroups.first { Path($0.name).lastComponentWithoutExtension == name } + + let fileReference: String + if let cachedFileReference = fileReferencesByPath[path] { + fileReference = cachedFileReference + } else { + let reference = PBXFileReference(reference: generateUUID(PBXFileReference.self, path.lastComponent), + sourceTree: .group, + name: variantGroup != nil ? localisationName : path.lastComponent, + path: filePath) + addObject(reference) + fileReference = reference.reference + fileReferencesByPath[path] = fileReference + } if let variantGroup = variantGroup { variantGroup.children.append(fileReference) From f2c440dd1dfcb50f654f74a87671f2e39a272f03 Mon Sep 17 00:00:00 2001 From: ryohey Date: Fri, 29 Sep 2017 14:44:17 +0900 Subject: [PATCH 4/4] update fixture --- .../project.pbxproj | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj index 384971a91..e5c2a4765 100644 --- a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj +++ b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj @@ -10,12 +10,13 @@ BF1073850101 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR1332263601 /* AppDelegate.swift */; }; BF1462768401 = {isa = PBXBuildFile; fileRef = FR2653659501 /* TestProjectTests.xctest */; }; BF1744565901 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR6218091901 /* ViewController.swift */; }; - BF1911148401 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = VG6405436301 /* LaunchScreen.storyboard */; }; + BF2250910101 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = VG2043127501 /* Main.storyboard */; }; + BF2445564001 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = VG2858723001 /* LaunchScreen.storyboard */; }; + BF2513089601 /* LocalizedStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = VG3182922801 /* LocalizedStoryboard.storyboard */; }; BF2753556301 = {isa = PBXBuildFile; fileRef = FR2993497801 /* MyFramework.framework */; }; BF3154421201 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FR5980633301 /* Assets.xcassets */; }; BF3515549501 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = FR7740960501 /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF3862341101 /* MyFramework.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = FR2993497801 /* MyFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - BF4946816301 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = VG1473702401 /* Main.storyboard */; }; BF5986511201 = {isa = PBXBuildFile; fileRef = FR6523263101 /* TestProject.app */; }; BF6182896901 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FR9215298301 /* Result.framework */; }; BF9001417701 /* TestProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR6877173101 /* TestProjectTests.swift */; }; @@ -57,18 +58,20 @@ FR1345298501 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; FR1345298502 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; FR1345298503 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FR1473702401 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; FR2653659501 /* TestProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = xctest; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = TestProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; FR2993497801 /* MyFramework.framework */ = {isa = PBXFileReference; explicitFileType = framework; includeInIndex = 0; lastKnownFileType = wrapper.framework; path = MyFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FR3546283901 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = ""; }; - FR3676338401 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - FR3676338402 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + FR4822987701 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LocalizedStoryboard.storyboard; sourceTree = ""; }; FR5980633301 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; FR6218091901 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; FR6334256101 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = ""; }; + FR6405436301 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; FR6523263101 /* TestProject.app */ = {isa = PBXFileReference; explicitFileType = app; includeInIndex = 0; lastKnownFileType = wrapper.application; path = TestProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; FR6877173101 /* TestProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectTests.swift; sourceTree = ""; }; FR7078510801 /* FrameworkFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkFile.swift; sourceTree = ""; }; FR7740960501 /* MyFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyFramework.h; sourceTree = ""; }; + FR8182352201 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LocalizedStoryboard.strings; sourceTree = ""; }; FR9215298301 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -138,8 +141,9 @@ FR5980633301 /* Assets.xcassets */, FR1345298502 /* Info.plist */, FR6218091901 /* ViewController.swift */, - VG6405436301 /* LaunchScreen.storyboard */, - VG1473702401 /* Main.storyboard */, + VG2858723001 /* LaunchScreen.storyboard */, + VG3182922801 /* LocalizedStoryboard.storyboard */, + VG2043127501 /* Main.storyboard */, ); name = TestProject; path = TestProject; @@ -305,8 +309,9 @@ buildActionMask = 2147483647; files = ( BF3154421201 /* Assets.xcassets in Resources */, - BF1911148401 /* LaunchScreen.storyboard in Resources */, - BF4946816301 /* Main.storyboard in Resources */, + BF2445564001 /* LaunchScreen.storyboard in Resources */, + BF2513089601 /* LocalizedStoryboard.storyboard in Resources */, + BF2250910101 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -415,22 +420,31 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - VG1473702401 /* Main.storyboard */ = { + VG2043127501 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( - FR3676338402 /* Base */, + FR1473702401 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; - VG6405436301 /* LaunchScreen.storyboard */ = { + VG2858723001 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( - FR3676338401 /* Base */, + FR6405436301 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; + VG3182922801 /* LocalizedStoryboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + FR4822987701 /* Base */, + FR8182352201 /* en */, + ); + name = LocalizedStoryboard.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */