mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2024-09-11 12:56:03 +03:00
Merge branch 'master' into katei/add-bundle-dependency
This commit is contained in:
commit
49f29e9156
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
||||
- name: Build
|
||||
run: swift build
|
||||
- name: Test
|
||||
run: swift test 2>&1 | xcpretty
|
||||
run: swift test
|
||||
- name: Gen fixtures
|
||||
run: scripts/gen-fixtures.sh
|
||||
- name: Check fixtures
|
||||
|
@ -6,12 +6,14 @@
|
||||
- Add Carthage static framework dependencies support. [#688](https://github.com/yonaskolb/XcodeGen/pull/688) @giginet
|
||||
- Added `xcodegen dump` command [#710](https://github.com/yonaskolb/XcodeGen/pull/710) @yonaskolb
|
||||
- Added `--no-env` option to disable environment variables expansion [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari
|
||||
- Added custom group support for target sources [#621](https://github.com/yonaskolb/XcodeGen/pull/621) @sroebert @rcari
|
||||
- Added new dependency type, `bundle`. This allows targets to copy bundles from other projects [#616](https://github.com/yonaskolb/XcodeGen/pull/616) @bsmith11
|
||||
|
||||
#### Fixed
|
||||
- Improved variable expansion runtime [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari
|
||||
- Fixed missing headers for static framework targets [#705](https://github.com/yonaskolb/XcodeGen/pull/705) @wag-miles
|
||||
- Using more file types from XcodeProj for PBXFileReferences resulting in less project diffs [#715](https://github.com/yonaskolb/XcodeGen/pull/715) @yonaskolb
|
||||
- Fixed localized `*.intentdefinition` not being added to build source phases [#720](https://github.com/yonaskolb/XcodeGen/pull/720) @giginet
|
||||
|
||||
#### Changed
|
||||
- Deprecated `$old_form` variables in favor of `${new_form}` variables [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari
|
||||
@ -37,7 +39,7 @@
|
||||
- Add base localisation by default even if no base localised files were found. Fixes warning in Xcode 11 [#685](https://github.com/yonaskolb/XcodeGen/pull/685) @yonaskolb
|
||||
- Don't generate CFBundleExecutable in default generated Info.plist for `bundle` target types [#689](https://github.com/yonaskolb/XcodeGen/pull/689) @FranzBusch
|
||||
- Fixed resolving relative paths with custom project destination [#681](https://github.com/yonaskolb/XcodeGen/pull/681) @giginet
|
||||
- Fixed resolving relative paths for Info.plist [#683](https://github.com/yonaskolb/XcodeGen/pull/683)
|
||||
- Fixed resolving relative paths for Info.plist [#683](https://github.com/yonaskolb/XcodeGen/pull/683) @giginet
|
||||
- Fixed macOS unit test target TEST_HOST [#696](https://github.com/yonaskolb/XcodeGen/pull/696) @mjarvis
|
||||
|
||||
#### Internal
|
||||
|
@ -309,6 +309,7 @@ A source can be provided via a string (the path) or an object of the form:
|
||||
|
||||
- [x] **path**: **String** - The path to the source file or directory.
|
||||
- [ ] **name**: **String** - Can be used to override the name of the source file or directory. By default the last component of the path is used for the name
|
||||
- [ ] **group**: **String** - Can be used to override the parent group of the source file or directory. By default a group is created at the root with the name of this source file or directory or intermediate groups are created if `createIntermediateGroups` is set to `true`. Multiple groups can be created by separating each one using a `/`. If multiple target sources share the same `group`, they will be put together in the same parent group.
|
||||
- [ ] **compilerFlags**: **[String]** or **String** - A list of compilerFlags to add to files under this specific path provided as a list or a space delimitted string. Defaults to empty.
|
||||
- [ ] **excludes**: **[String]** - A list of [global patterns](https://en.wikipedia.org/wiki/Glob_(programming)) representing the files to exclude. These rules are relative to `path` and _not the directory where `project.yml` resides_. XcodeGen uses Bash 4's Glob behaviors where globstar (**) is enabled.
|
||||
- [ ] **includes**: **[String]** - A list of global patterns in the same format as `excludes` representing the files to include. These rules are relative to `path` and _not the directory where `project.yml` resides_. If **excludes** is present and file conflicts with **includes**, **excludes** will override the **includes** behavior.
|
||||
|
@ -9,6 +9,7 @@ public struct TargetSource: Equatable {
|
||||
|
||||
public var path: String
|
||||
public var name: String?
|
||||
public var group: String?
|
||||
public var compilerFlags: [String]
|
||||
public var excludes: [String]
|
||||
public var includes: [String]
|
||||
@ -124,6 +125,7 @@ public struct TargetSource: Equatable {
|
||||
public init(
|
||||
path: String,
|
||||
name: String? = nil,
|
||||
group: String? = nil,
|
||||
compilerFlags: [String] = [],
|
||||
excludes: [String] = [],
|
||||
includes: [String] = [],
|
||||
@ -136,6 +138,7 @@ public struct TargetSource: Equatable {
|
||||
) {
|
||||
self.path = path
|
||||
self.name = name
|
||||
self.group = group
|
||||
self.compilerFlags = compilerFlags
|
||||
self.excludes = excludes
|
||||
self.includes = includes
|
||||
@ -168,6 +171,7 @@ extension TargetSource: JSONObjectConvertible {
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
path = try jsonDictionary.json(atKeyPath: "path")
|
||||
name = jsonDictionary.json(atKeyPath: "name")
|
||||
group = jsonDictionary.json(atKeyPath: "group")
|
||||
|
||||
let maybeCompilerFlagsString: String? = jsonDictionary.json(atKeyPath: "compilerFlags")
|
||||
let maybeCompilerFlagsArray: [String]? = jsonDictionary.json(atKeyPath: "compilerFlags")
|
||||
@ -198,6 +202,7 @@ extension TargetSource: JSONEncodable {
|
||||
"excludes": excludes,
|
||||
"includes": includes,
|
||||
"name": name,
|
||||
"group": group,
|
||||
"headerVisibility": headerVisibility?.rawValue,
|
||||
"type": type?.rawValue,
|
||||
"buildPhase": buildPhase?.toJSONValue(),
|
||||
|
@ -81,8 +81,8 @@ class SourceGenerator {
|
||||
_ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), path: fullPath)
|
||||
}
|
||||
|
||||
func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, buildPhase: TargetSource.BuildPhase? = nil) -> SourceFile {
|
||||
let fileReference = fileReferencesByPath[path.string.lowercased()]!
|
||||
func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, buildPhase: TargetSource.BuildPhase? = nil, fileReference: PBXFileElement? = nil) -> SourceFile {
|
||||
let fileReference = fileReference ?? fileReferencesByPath[path.string.lowercased()]!
|
||||
var settings: [String: Any] = [:]
|
||||
var attributes: [String] = targetSource.attributes
|
||||
var chosenBuildPhase: TargetSource.BuildPhase?
|
||||
@ -143,6 +143,7 @@ class SourceGenerator {
|
||||
path: parentPath,
|
||||
mergingChildren: [fileReference],
|
||||
createIntermediateGroups: createIntermediateGroups,
|
||||
hasCustomParent: false,
|
||||
isBaseGroup: true
|
||||
)
|
||||
|
||||
@ -270,7 +271,7 @@ class SourceGenerator {
|
||||
|
||||
/// Create a group or return an existing one at the path.
|
||||
/// Any merged children are added to a new group or merged into an existing one.
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [PBXFileElement], createIntermediateGroups: Bool, isBaseGroup: Bool) -> PBXGroup {
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [PBXFileElement], createIntermediateGroups: Bool, hasCustomParent: Bool, isBaseGroup: Bool) -> PBXGroup {
|
||||
let groupReference: PBXGroup
|
||||
|
||||
if let cachedGroup = groupsByPath[path] {
|
||||
@ -280,6 +281,7 @@ class SourceGenerator {
|
||||
// Check equality by path and sourceTree because XcodeProj.PBXObject.== is very slow.
|
||||
if !cachedGroupChildren.contains(where: { $0.name == child.name && $0.path == child.path && $0.sourceTree == child.sourceTree }) {
|
||||
cachedGroupChildren.append(child)
|
||||
child.parent = cachedGroup
|
||||
}
|
||||
}
|
||||
cachedGroup.children = cachedGroupChildren
|
||||
@ -293,10 +295,11 @@ class SourceGenerator {
|
||||
let isRootPath = (isBaseGroup && isOutOfBasePath) || path.parent() == project.basePath
|
||||
|
||||
// is a top level group in the project
|
||||
let isTopLevelGroup = (isBaseGroup && !createIntermediateGroups) || isRootPath
|
||||
let isTopLevelGroup = !hasCustomParent && ((isBaseGroup && !createIntermediateGroups) || isRootPath)
|
||||
|
||||
let groupName = name ?? path.lastComponent
|
||||
let groupPath = resolveGroupPath(path, isTopLevelGroup: isTopLevelGroup)
|
||||
|
||||
let groupPath = resolveGroupPath(path, isTopLevelGroup: hasCustomParent || isTopLevelGroup)
|
||||
|
||||
let group = PBXGroup(
|
||||
children: children,
|
||||
@ -387,11 +390,20 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
/// creates all the source files and groups they belong to for a given targetSource
|
||||
private func getGroupSources(targetType: PBXProductType, targetSource: TargetSource, path: Path, isBaseGroup: Bool, excludePaths: Set<Path>, includePaths: Set<Path>)
|
||||
throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
|
||||
private func getGroupSources(
|
||||
targetType: PBXProductType,
|
||||
targetSource: TargetSource,
|
||||
path: Path,
|
||||
isBaseGroup: Bool,
|
||||
hasCustomParent: Bool,
|
||||
excludePaths: Set<Path>,
|
||||
includePaths: Set<Path>
|
||||
) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
|
||||
|
||||
let children = try getSourceChildren(targetSource: targetSource, dirPath: path, excludePaths: excludePaths, includePaths: includePaths)
|
||||
|
||||
let createIntermediateGroups = targetSource.createIntermediateGroups ?? project.options.createIntermediateGroups
|
||||
|
||||
let directories = children
|
||||
.filter { $0.isDirectory && $0.extension == nil && $0.extension != "lproj" }
|
||||
|
||||
@ -408,12 +420,16 @@ class SourceGenerator {
|
||||
var groups: [PBXGroup] = []
|
||||
|
||||
for path in directories {
|
||||
let subGroups = try getGroupSources(targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: path,
|
||||
isBaseGroup: false,
|
||||
excludePaths: excludePaths,
|
||||
includePaths: includePaths)
|
||||
|
||||
let subGroups = try getGroupSources(
|
||||
targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: path,
|
||||
isBaseGroup: false,
|
||||
hasCustomParent: false,
|
||||
excludePaths: excludePaths,
|
||||
includePaths: includePaths
|
||||
)
|
||||
|
||||
guard !subGroups.sourceFiles.isEmpty || project.options.generateEmptyDirectories else {
|
||||
continue
|
||||
@ -452,12 +468,10 @@ class SourceGenerator {
|
||||
groupChildren.append(variantGroup)
|
||||
baseLocalisationVariantGroups.append(variantGroup)
|
||||
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: variantGroup,
|
||||
buildFile: PBXBuildFile(file: variantGroup),
|
||||
buildPhase: .resources
|
||||
)
|
||||
let sourceFile = generateSourceFile(targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: filePath,
|
||||
fileReference: variantGroup)
|
||||
allSourceFiles.append(sourceFile)
|
||||
}
|
||||
}
|
||||
@ -491,24 +505,21 @@ class SourceGenerator {
|
||||
}
|
||||
} else {
|
||||
// add SourceFile to group if there is no Base.lproj directory
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: fileReference,
|
||||
buildFile: PBXBuildFile(file: fileReference),
|
||||
buildPhase: .resources
|
||||
)
|
||||
let sourceFile = generateSourceFile(targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: filePath,
|
||||
fileReference: fileReference)
|
||||
allSourceFiles.append(sourceFile)
|
||||
groupChildren.append(fileReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let createIntermediateGroups = targetSource.createIntermediateGroups ?? project.options.createIntermediateGroups
|
||||
|
||||
let group = getGroup(
|
||||
path: path,
|
||||
mergingChildren: groupChildren,
|
||||
createIntermediateGroups: createIntermediateGroups,
|
||||
hasCustomParent: hasCustomParent,
|
||||
isBaseGroup: isBaseGroup
|
||||
)
|
||||
if createIntermediateGroups {
|
||||
@ -528,6 +539,10 @@ class SourceGenerator {
|
||||
let includePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.includes)
|
||||
|
||||
let type = targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group)
|
||||
|
||||
let customParentGroups = (targetSource.group ?? "").split(separator: "/").map{ String($0) }
|
||||
let hasCustomParent = !customParentGroups.isEmpty
|
||||
|
||||
let createIntermediateGroups = targetSource.createIntermediateGroups ?? project.options.createIntermediateGroups
|
||||
|
||||
var sourceFiles: [SourceFile] = []
|
||||
@ -544,7 +559,7 @@ class SourceGenerator {
|
||||
lastKnownFileType: "folder"
|
||||
)
|
||||
|
||||
if !createIntermediateGroups || path.parent() == project.basePath {
|
||||
if !(createIntermediateGroups || hasCustomParent) || path.parent() == project.basePath {
|
||||
rootGroups.insert(fileReference)
|
||||
}
|
||||
|
||||
@ -565,12 +580,21 @@ class SourceGenerator {
|
||||
|
||||
let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path)
|
||||
|
||||
if parentPath == project.basePath {
|
||||
if hasCustomParent {
|
||||
sourcePath = path
|
||||
sourceReference = fileReference
|
||||
} else if parentPath == project.basePath {
|
||||
sourcePath = path
|
||||
sourceReference = fileReference
|
||||
rootGroups.insert(fileReference)
|
||||
} else {
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileReference], createIntermediateGroups: createIntermediateGroups, isBaseGroup: true)
|
||||
let parentGroup = getGroup(
|
||||
path: parentPath,
|
||||
mergingChildren: [fileReference],
|
||||
createIntermediateGroups: createIntermediateGroups,
|
||||
hasCustomParent: hasCustomParent,
|
||||
isBaseGroup: true
|
||||
)
|
||||
sourcePath = parentPath
|
||||
sourceReference = parentGroup
|
||||
}
|
||||
@ -581,12 +605,17 @@ class SourceGenerator {
|
||||
// This group is missing, so if's optional just return an empty array
|
||||
return []
|
||||
}
|
||||
let (groupSourceFiles, groups) = try getGroupSources(targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: path,
|
||||
isBaseGroup: true,
|
||||
excludePaths: excludePaths,
|
||||
includePaths: includePaths)
|
||||
|
||||
let (groupSourceFiles, groups) = try getGroupSources(
|
||||
targetType: targetType,
|
||||
targetSource: targetSource,
|
||||
path: path,
|
||||
isBaseGroup: true,
|
||||
hasCustomParent: hasCustomParent,
|
||||
excludePaths: excludePaths,
|
||||
includePaths: includePaths
|
||||
)
|
||||
|
||||
let group = groups.first!
|
||||
if let name = targetSource.name {
|
||||
group.name = name
|
||||
@ -596,13 +625,44 @@ class SourceGenerator {
|
||||
sourceReference = group
|
||||
}
|
||||
|
||||
if createIntermediateGroups {
|
||||
if hasCustomParent {
|
||||
createParentGroups(customParentGroups, for: sourceReference)
|
||||
try makePathRelative(for: sourceReference, at: path)
|
||||
} else if createIntermediateGroups {
|
||||
createIntermediaGroups(for: sourceReference, at: sourcePath)
|
||||
}
|
||||
|
||||
return sourceFiles
|
||||
}
|
||||
|
||||
private func createParentGroups(_ parentGroups: [String], for fileElement: PBXFileElement) {
|
||||
guard let parentName = parentGroups.last else {
|
||||
return
|
||||
}
|
||||
|
||||
let parentPath = project.basePath + Path(parentGroups.joined(separator: "/"))
|
||||
let parentPathExists = parentPath.exists
|
||||
let parentGroupAlreadyExists = groupsByPath[parentPath] != nil
|
||||
|
||||
let parentGroup = getGroup(
|
||||
path: parentPath,
|
||||
mergingChildren: [fileElement],
|
||||
createIntermediateGroups: false,
|
||||
hasCustomParent: false,
|
||||
isBaseGroup: parentGroups.count == 1
|
||||
)
|
||||
|
||||
// As this path is a custom group, remove the path reference
|
||||
if !parentPathExists {
|
||||
parentGroup.name = String(parentName)
|
||||
parentGroup.path = nil
|
||||
}
|
||||
|
||||
if !parentGroupAlreadyExists {
|
||||
createParentGroups(parentGroups.dropLast(), for: parentGroup)
|
||||
}
|
||||
}
|
||||
|
||||
// Add groups for all parents recursively
|
||||
private func createIntermediaGroups(for fileElement: PBXFileElement, at path: Path) {
|
||||
|
||||
@ -613,13 +673,45 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
let hasParentGroup = groupsByPath[parentPath] != nil
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileElement], createIntermediateGroups: true, isBaseGroup: false)
|
||||
let parentGroup = getGroup(
|
||||
path: parentPath,
|
||||
mergingChildren: [fileElement],
|
||||
createIntermediateGroups: true,
|
||||
hasCustomParent: false,
|
||||
isBaseGroup: false
|
||||
)
|
||||
|
||||
if !hasParentGroup {
|
||||
createIntermediaGroups(for: parentGroup, at: parentPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Make the fileElement path and name relative to its parents aggregated paths
|
||||
private func makePathRelative(for fileElement: PBXFileElement, at path: Path) throws {
|
||||
// This makes the fileElement path relative to its parent and not to the project. Xcode then rebuilds the actual
|
||||
// path for the file based on the hierarchy this fileElement lives in.
|
||||
var paths: [String] = []
|
||||
var element: PBXFileElement = fileElement
|
||||
while true {
|
||||
guard let parent = element.parent else { break }
|
||||
|
||||
if let path = parent.path {
|
||||
paths.insert(path, at: 0)
|
||||
}
|
||||
|
||||
element = parent
|
||||
}
|
||||
|
||||
let completePath = project.basePath + Path(paths.joined(separator: "/"))
|
||||
let relativePath = try path.relativePath(from: completePath)
|
||||
let relativePathString = relativePath.string
|
||||
|
||||
if relativePathString != fileElement.path {
|
||||
fileElement.path = relativePathString
|
||||
fileElement.name = relativePath.lastComponent
|
||||
}
|
||||
}
|
||||
|
||||
private func findCurrentCoreDataModelVersionPath(using versionedModels: [Path]) -> Path? {
|
||||
// Find and parse the current version model stored in the .xccurrentversion file
|
||||
guard
|
||||
|
@ -23,13 +23,13 @@ extension PBXProj {
|
||||
var string = group.nameOrPath
|
||||
for child in group.children {
|
||||
if let group = child as? PBXGroup {
|
||||
string += "\n 📁 " + printGroup(group: group).replacingOccurrences(of: "\n ", with: "\n ")
|
||||
string += "\n 📁 " + printGroup(group: group).replacingOccurrences(of: "\n ", with: "\n ")
|
||||
} else if let fileReference = child as? PBXFileReference {
|
||||
string += "\n 📄 " + fileReference.nameOrPath
|
||||
string += "\n 📄 " + fileReference.nameOrPath
|
||||
} else if let variantGroup = child as? PBXVariantGroup {
|
||||
string += "\n 🌎 " + variantGroup.nameOrPath
|
||||
string += "\n 🌎 " + variantGroup.nameOrPath
|
||||
} else if let versionGroup = child as? XCVersionGroup {
|
||||
string += "\n 🔢 " + versionGroup.nameOrPath
|
||||
string += "\n 🔢 " + versionGroup.nameOrPath
|
||||
}
|
||||
}
|
||||
return string
|
||||
|
0
Tests/Fixtures/TestProject/Group/File1.swift
Normal file
0
Tests/Fixtures/TestProject/Group/File1.swift
Normal file
0
Tests/Fixtures/TestProject/Group2/File2.swift
Normal file
0
Tests/Fixtures/TestProject/Group2/File2.swift
Normal file
@ -52,6 +52,7 @@
|
||||
307B5322FC5A220652BA6FE0 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; };
|
||||
3133B36F3898A27A2B1C56FC /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; };
|
||||
3318F40C855184C18197ED30 /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; };
|
||||
339578307B9266AB3D7722D9 /* File2.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC56891DA7446EAC8C2F27EB /* File2.swift */; };
|
||||
3535891EC86283BB5064E7E1 /* Headers in Headers */ = {isa = PBXBuildFile; fileRef = 2E1E747C7BC434ADB80CC269 /* Headers */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3788E1382B38DF4ACE3D2BB1 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3C5134EE524310ACF7B7CD6E /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CAF6C55B555E3E1352645B6 /* ExtensionDelegate.swift */; };
|
||||
@ -74,6 +75,7 @@
|
||||
632774E7F21CCB386A76B2A8 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B198242976C3395E31FE000A /* MessagesViewController.swift */; };
|
||||
63D8E7F00276736EDA62D227 /* Framework2.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
666AA5F3F63C8FD7C68A6CC5 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
666DEC173BC78C7641AB22EC /* File1.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE1343F2238429D4DA9D830B /* File1.swift */; };
|
||||
66C3C5E3C13325F351A3008F /* module.modulemap in CopyFiles */ = {isa = PBXBuildFile; fileRef = F2950763C4C568CC85021D18 /* module.modulemap */; };
|
||||
6E8F8303759824631C8D9DA3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E17D598D98065767A04740F /* Localizable.strings */; };
|
||||
7148A4172BFA1CC22E6ED5DB /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 753001CDCEAA4C4E1AFF8E87 /* MainInterface.storyboard */; };
|
||||
@ -443,6 +445,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
020E4DA91C9132845CAFDC5D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
039F208D1138598CE060F140 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
03D6D1E34022DA9524E5B38D /* Mintfile */ = {isa = PBXFileReference; path = Mintfile; sourceTree = "<group>"; };
|
||||
056A43A09CE7E88D578696D8 /* StaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = StaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
068EDF47F0B087F6A4052AC0 /* Empty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Empty.h; sourceTree = "<group>"; };
|
||||
0704B6CAFBB53E0EBB08F6B3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
@ -518,8 +521,8 @@
|
||||
B76E17CE3574081D5BF45B44 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = "<group>"; };
|
||||
BA040F1F7D6CA08878323A55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
BB178D03E75929F3F5B10C56 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = "<group>"; };
|
||||
BC56891DA7446EAC8C2F27EB /* File2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = File2.swift; path = Group2/File2.swift; sourceTree = "<group>"; };
|
||||
BECEA4A483ADEB8158F640B3 /* Tool */ = {isa = PBXFileReference; includeInIndex = 0; path = Tool; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C2F3574CCEF023755DDB1A06 /* Mintfile */ = {isa = PBXFileReference; path = Mintfile; sourceTree = "<group>"; };
|
||||
C53ACB2962FED621389C36A2 /* iMessageStickersExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = iMessageStickersExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C7809CE9FE9852C2AA87ACE5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
C934C1F7A68CCD0AB6B38478 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = "<group>"; };
|
||||
@ -534,17 +537,18 @@
|
||||
D70BE0C05E5779A077793BE6 /* Model 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 2.xcdatamodel"; sourceTree = "<group>"; };
|
||||
D8A016580A3B8F72B820BFBF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
D8D8907E2CDA1295D0D94F53 /* StaticLibrary_Swift.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = StaticLibrary_Swift.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DAA7880242A9DE61E68026CC /* Folder */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Folder; sourceTree = SOURCE_ROOT; };
|
||||
E2AF3B572B3B2E815DA1844D /* BundleA.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = BundleA.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E42335D1200CB7B8B91E962F /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
E43116070AFEF5D8C3A5A957 /* TestFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E55F45EACB0F382722D61C8D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
E9672EF8FE1DDC8DE0705129 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
|
||||
EE1343F2238429D4DA9D830B /* File1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = File1.swift; path = Group/File1.swift; sourceTree = "<group>"; };
|
||||
EF92E90B6F1D583382BD85BE /* StaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = StaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F0D48A913C087D049C8EDDD7 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
F2950763C4C568CC85021D18 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
F2FA55A558627ED576A4AFD6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
FA86D418796C1A6864414460 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
FC60FF5527FEDF545816FFCF /* Folder */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Folder; sourceTree = SOURCE_ROOT; };
|
||||
FD05F36F95D6F098A76F220B /* XPC_Service.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPC_Service.h; sourceTree = "<group>"; };
|
||||
FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
FDB2B6A77D39CD5602F2125F /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; };
|
||||
@ -702,6 +706,7 @@
|
||||
795B8D70B674C850B57DD39D /* App_watchOS Extension */,
|
||||
6DBE0EE90642BB3F6E58AD43 /* Configs */,
|
||||
3F2E22B7AB20FA42CD205C2A /* CopyFiles */,
|
||||
FCC084D4F8992BBC49983A38 /* CustomGroup */,
|
||||
5CBCE0E2A145046265FE99E2 /* FileGroup */,
|
||||
1A57D1EE1FBC13598F6B5CB0 /* Framework */,
|
||||
A3DCF90D9B1EF4E27CF54B19 /* iMessageApp */,
|
||||
@ -714,9 +719,8 @@
|
||||
8CFD8AD4820FAB9265663F92 /* Tool */,
|
||||
3FEA12CF227D41EF50E5C2DB /* Vendor */,
|
||||
80C3A0E524EC1ABCB9149EA2 /* XPC Service */,
|
||||
FC60FF5527FEDF545816FFCF /* Folder */,
|
||||
DAA7880242A9DE61E68026CC /* Folder */,
|
||||
2E1E747C7BC434ADB80CC269 /* Headers */,
|
||||
C2F3574CCEF023755DDB1A06 /* Mintfile */,
|
||||
6B1603BA83AA0C7B94E45168 /* ResourceFolder */,
|
||||
6BBE762F36D94AB6FFBFE834 /* SomeFile */,
|
||||
79DC4A1E4D2E0D3A215179BC /* Bundles */,
|
||||
@ -982,6 +986,17 @@
|
||||
path = App_iOS_Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FCC084D4F8992BBC49983A38 /* CustomGroup */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE1343F2238429D4DA9D830B /* File1.swift */,
|
||||
BC56891DA7446EAC8C2F27EB /* File2.swift */,
|
||||
DAA7880242A9DE61E68026CC /* Folder */,
|
||||
03D6D1E34022DA9524E5B38D /* Mintfile */,
|
||||
);
|
||||
name = CustomGroup;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@ -1951,6 +1966,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
09617AB755651FFEB2564CBC /* AppDelegate.swift in Sources */,
|
||||
666DEC173BC78C7641AB22EC /* File1.swift in Sources */,
|
||||
339578307B9266AB3D7722D9 /* File2.swift in Sources */,
|
||||
F788A3FA1CE6489BC257C1C3 /* Model.xcdatamodeld in Sources */,
|
||||
58C18019E71E372F635A3FB4 /* MoreUnder.swift in Sources */,
|
||||
5D10822B0E7C33DD6979F656 /* Standalone.swift in Sources */,
|
||||
|
@ -72,9 +72,15 @@ targets:
|
||||
- path: Folder
|
||||
type: folder
|
||||
buildPhase: none
|
||||
group: CustomGroup
|
||||
- path: Mintfile
|
||||
type: file
|
||||
buildPhase: none
|
||||
group: CustomGroup
|
||||
- path: Group/File1.swift
|
||||
group: CustomGroup
|
||||
- path: Group2/File2.swift
|
||||
group: CustomGroup
|
||||
- path: CopyFiles
|
||||
buildPhase:
|
||||
copyFiles:
|
||||
|
@ -912,7 +912,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
], localPackages: ["../XcodeGen"], options: .init(localPackagesGroup: "MyPackages"))
|
||||
|
||||
let pbxProject = try project.generatePbxProj(specValidate: false)
|
||||
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == "dfg" }))
|
||||
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
|
||||
|
||||
let projectSpecDependency = try unwrap(nativeTarget.packageProductDependencies.first(where: { $0.productName == "ProjectSpec" }))
|
||||
|
||||
|
@ -470,6 +470,44 @@ class SourceGeneratorTests: XCTestCase {
|
||||
try pbxProj.expectFile(paths: ["Sources/B", "b.swift"], names: ["B", "b.swift"], buildPhase: .sources)
|
||||
}
|
||||
|
||||
$0.it("generates custom groups") {
|
||||
|
||||
let directories = """
|
||||
- Sources:
|
||||
- a.swift
|
||||
- A:
|
||||
- b.swift
|
||||
- F:
|
||||
- G:
|
||||
- h.swift
|
||||
- i.swift
|
||||
- B:
|
||||
- b.swift
|
||||
- C:
|
||||
- c.swift
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: [
|
||||
TargetSource(path: "Sources/a.swift", group: "CustomGroup1"),
|
||||
TargetSource(path: "Sources/A/b.swift", group: "CustomGroup1"),
|
||||
TargetSource(path: "Sources/F/G/h.swift", group: "CustomGroup1"),
|
||||
TargetSource(path: "Sources/B", group: "CustomGroup2", createIntermediateGroups: false),
|
||||
TargetSource(path: "Sources/F/G/i.swift", group: "Sources/F/G/CustomGroup3"),
|
||||
])
|
||||
|
||||
let options = SpecOptions(createIntermediateGroups: true)
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: options)
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
try pbxProj.expectFile(paths: ["CustomGroup1", "Sources/a.swift"], names: ["CustomGroup1", "a.swift"], buildPhase: .sources)
|
||||
try pbxProj.expectFile(paths: ["CustomGroup1", "Sources/A/b.swift"], names: ["CustomGroup1", "b.swift"], buildPhase: .sources)
|
||||
try pbxProj.expectFile(paths: ["CustomGroup1", "Sources/F/G/h.swift"], names: ["CustomGroup1", "h.swift"], buildPhase: .sources)
|
||||
try pbxProj.expectFile(paths: ["Sources", "F", "G", "CustomGroup3", "i.swift"], names: ["Sources", "F", "G", "CustomGroup3", "i.swift"], buildPhase: .sources)
|
||||
try pbxProj.expectFile(paths: ["CustomGroup2", "Sources/B", "b.swift"], names: ["CustomGroup2", "B", "b.swift"], buildPhase: .sources)
|
||||
try pbxProj.expectFile(paths: ["CustomGroup2", "Sources/B", "C", "c.swift"], names: ["CustomGroup2", "B", "C", "c.swift"], buildPhase: .sources)
|
||||
}
|
||||
|
||||
$0.it("generates folder references") {
|
||||
let directories = """
|
||||
Sources:
|
||||
@ -833,6 +871,64 @@ class SourceGeneratorTests: XCTestCase {
|
||||
try pbxProj.expectFileMissing(paths: ["Sources", "group2", "file.swift"])
|
||||
try pbxProj.expectFileMissing(paths: ["Sources", "group", "file.swift"])
|
||||
}
|
||||
|
||||
$0.describe("Localized sources") {
|
||||
$0.context("With localized sources") {
|
||||
$0.it("*.intentdefinition should be added to source phase") {
|
||||
let directories = """
|
||||
Sources:
|
||||
Base.lproj:
|
||||
- Intents.intentdefinition
|
||||
en.lproj:
|
||||
- Intents.strings
|
||||
ja.lproj:
|
||||
- Intents.strings
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
let directoryPath = Path("TestDirectory")
|
||||
|
||||
let target = Target(name: "IntentDefinitions",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
sources: [TargetSource(path: "Sources")])
|
||||
let project = Project(basePath: directoryPath,
|
||||
name: "IntendDefinitions",
|
||||
targets: [target])
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let sourceBuildPhase = try unwrap(pbxProj.buildPhases.first { $0.buildPhase == .sources })
|
||||
try expect(sourceBuildPhase.files?.compactMap { $0.file?.nameOrPath }) == ["Intents.intentdefinition"]
|
||||
}
|
||||
}
|
||||
|
||||
$0.context("With localized sources with buildPhase") {
|
||||
$0.it("*.intentdefinition with buildPhase should be added to resource phase") {
|
||||
let directories = """
|
||||
Sources:
|
||||
Base.lproj:
|
||||
- Intents.intentdefinition
|
||||
en.lproj:
|
||||
- Intents.strings
|
||||
ja.lproj:
|
||||
- Intents.strings
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
let directoryPath = Path("TestDirectory")
|
||||
|
||||
let target = Target(name: "IntentDefinitions",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
sources: [TargetSource(path: "Sources", buildPhase: .resources)])
|
||||
let project = Project(basePath: directoryPath,
|
||||
name: "IntendDefinitions",
|
||||
targets: [target])
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let sourceBuildPhase = try unwrap(pbxProj.buildPhases.first { $0.buildPhase == .sources })
|
||||
let resourcesBuildPhase = try unwrap(pbxProj.buildPhases.first { $0.buildPhase == .resources })
|
||||
try expect(sourceBuildPhase.files) == []
|
||||
try expect(resourcesBuildPhase.files?.compactMap { $0.file?.nameOrPath }) == ["Intents.intentdefinition"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -846,6 +942,7 @@ extension PBXProj {
|
||||
if let names = names, names != paths {
|
||||
error += " and name \(names.joined(separator: "/").quoted)"
|
||||
}
|
||||
error += "\n\(self.printGroups())"
|
||||
throw failure(error, file: file, line: line)
|
||||
}
|
||||
|
||||
@ -895,18 +992,22 @@ extension PBXProj {
|
||||
}
|
||||
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> PBXFileReference? {
|
||||
guard !paths.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard !paths.isEmpty else { return nil }
|
||||
let path = paths.first!
|
||||
let name = names.first!
|
||||
let restOfPath = Array(paths.dropFirst())
|
||||
let restOfName = Array(names.dropFirst())
|
||||
if restOfPath.isEmpty {
|
||||
let fileReferences: [PBXFileReference] = group.children.compactMap { $0 as? PBXFileReference }
|
||||
return fileReferences.first { $0.path == path && $0.nameOrPath == name }
|
||||
return fileReferences.first { ($0.path == nil || $0.path == path) && $0.nameOrPath == name }
|
||||
} else {
|
||||
let groups = group.children.compactMap { $0 as? PBXGroup }
|
||||
guard let group = groups.first(where: { $0.path == path && $0.nameOrPath == name }) else { return nil }
|
||||
guard let group = groups.first(where: { ($0.path == nil || $0.path == path) && $0.nameOrPath == name }) else {
|
||||
return nil
|
||||
}
|
||||
return getFileReference(group: group, paths: restOfPath, names: restOfName)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user