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

Fix localisation variant groups #70

Merged
merged 4 commits into from
Oct 16, 2017
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
38 changes: 26 additions & 12 deletions Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -57,18 +58,20 @@
FR1345298501 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FR1345298502 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FR1345298503 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FR1473702401 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
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 = "<group>"; };
FR3676338401 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
FR3676338402 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
FR4822987701 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LocalizedStoryboard.storyboard; sourceTree = "<group>"; };
FR5980633301 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
FR6218091901 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
FR6334256101 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = "<group>"; };
FR6405436301 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
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 = "<group>"; };
FR7078510801 /* FrameworkFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkFile.swift; sourceTree = "<group>"; };
FR7740960501 /* MyFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyFramework.h; sourceTree = "<group>"; };
FR8182352201 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LocalizedStoryboard.strings; sourceTree = "<group>"; };
FR9215298301 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 = "<group>";
};
VG6405436301 /* LaunchScreen.storyboard */ = {
VG2858723001 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
FR3676338401 /* Base */,
FR6405436301 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
VG3182922801 /* LocalizedStoryboard.storyboard */ = {
isa = PBXVariantGroup;
children = (
FR4822987701 /* Base */,
FR8182352201 /* en */,
);
name = LocalizedStoryboard.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
</dependencies>
<scenes/>
</document>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

84 changes: 65 additions & 19 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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] = [:]
Expand Down Expand Up @@ -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)
}

Expand All @@ -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
Expand Down Expand Up @@ -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 }
}

Expand Down Expand Up @@ -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"]

Expand All @@ -484,34 +485,79 @@ 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 } {


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 { 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
}

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)
}
}
}

Expand All @@ -528,6 +574,6 @@ public class PBXProjGenerator {
groupsByPath[path] = group
}
groups.insert(group, at: 0)
return (allFilePaths, groups)
return (allSourceFiles, groups)
}
}
38 changes: 36 additions & 2 deletions Tests/XcodeGenKitTests/FixtureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just for visual grouping? Otherwise the it function is throwing so you don't need to wrap in a do

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's just for visual grouping.

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
}
}
}
}