Add support for SPM dependencies with Core Data models (#4237)
* Improve opaque folders detection like xcdatamodeld, docc and playground * Add test_isInOpaqueDirectory * Add code review comment * Add fixture for CoreData example * chore: lint * Fix duplicated core data models in build phase * Build to specific simulator Co-authored-by: Daniele Formichelli <df@bendingspoons.com>
This commit is contained in:
parent
a72d6ae855
commit
6001d23278
|
@ -7,6 +7,8 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
### Added
|
||||
|
||||
- Add `.optional` option to `.cloud` [#4262](https://github.com/tuist/tuist/pull/4262) by [@fortmarek](https://github.com/fortmarek).
|
||||
- Add support for SPM dependencies with Core Data models. [#4237](https://github.com/tuist/tuist/pull/4237) by [@adellibovi](https://github.com/adellibovi)
|
||||
- Add support for Core Data models in Resources. [#4237](https://github.com/tuist/tuist/pull/4237) by [@adellibovi](https://github.com/adellibovi)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@ extension Target {
|
|||
let paths: [AbsolutePath]
|
||||
|
||||
do {
|
||||
paths = try base.throwingGlob(sourcePath.basename)
|
||||
paths = try FileHandler.shared
|
||||
.throwingGlob(base, glob: sourcePath.basename)
|
||||
.filter { !$0.isInOpaqueDirectory }
|
||||
} catch let GlobError.nonExistentDirectory(invalidGlob) {
|
||||
paths = []
|
||||
invalidGlobs.append(invalidGlob)
|
||||
|
|
|
@ -194,9 +194,7 @@ final class BuildPhaseGenerator: BuildPhaseGenerating {
|
|||
pbxTarget.buildPhases.append(sourcesBuildPhase)
|
||||
|
||||
var buildFilesCache = Set<AbsolutePath>()
|
||||
// Ignore DocC Swift tutorial files from `Sources`
|
||||
let sortedFiles = files
|
||||
.filter { !fileElements.isDocCTutorialFile(path: $0.path) }
|
||||
.sorted(by: { $0.path < $1.path })
|
||||
|
||||
var pbxBuildFiles = [PBXBuildFile]()
|
||||
|
@ -378,14 +376,6 @@ final class BuildPhaseGenerator: BuildPhaseGenerating {
|
|||
let pathString = buildFilePath.pathString
|
||||
let isLocalized = pathString.contains(".lproj/")
|
||||
let isLproj = buildFilePath.extension == "lproj"
|
||||
let isWithinAssets = pathString.contains(".xcassets/") || pathString.contains(".scnassets/")
|
||||
|
||||
/// Assets that are part of a .xcassets or .scnassets folder
|
||||
/// are not added individually. The whole folder is added
|
||||
/// instead as a group.
|
||||
if isWithinAssets {
|
||||
return
|
||||
}
|
||||
|
||||
var element: (element: PBXFileElement, path: AbsolutePath)?
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ class ProjectFileElements {
|
|||
toGroup: toGroup,
|
||||
pbxproj: pbxproj
|
||||
)
|
||||
} else if !(isFolderTypeFileSource(path: absolutePath) || isLeaf) {
|
||||
} else if !isLeaf {
|
||||
return addGroupElement(
|
||||
from: from,
|
||||
folderAbsolutePath: absolutePath,
|
||||
|
@ -376,17 +376,6 @@ class ProjectFileElements {
|
|||
toGroup: toGroup,
|
||||
pbxproj: pbxproj
|
||||
)
|
||||
} else if isPlayground(path: absolutePath) {
|
||||
addPlayground(
|
||||
from: from,
|
||||
fileAbsolutePath: absolutePath,
|
||||
fileRelativePath: relativePath,
|
||||
name: name,
|
||||
toGroup: toGroup,
|
||||
pbxproj: pbxproj
|
||||
)
|
||||
return nil
|
||||
|
||||
} else {
|
||||
addFileElement(
|
||||
from: from,
|
||||
|
@ -521,32 +510,13 @@ class ProjectFileElements {
|
|||
pbxproj: PBXProj
|
||||
) {
|
||||
let lastKnownFileType = fileAbsolutePath.extension.flatMap { Xcode.filetype(extension: $0) }
|
||||
let file = PBXFileReference(
|
||||
sourceTree: .group,
|
||||
name: name,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: fileRelativePath.pathString
|
||||
)
|
||||
pbxproj.add(object: file)
|
||||
toGroup.children.append(file)
|
||||
elements[fileAbsolutePath] = file
|
||||
}
|
||||
|
||||
func addPlayground(
|
||||
from _: AbsolutePath,
|
||||
fileAbsolutePath: AbsolutePath,
|
||||
fileRelativePath: RelativePath,
|
||||
name: String?,
|
||||
toGroup: PBXGroup,
|
||||
pbxproj: PBXProj
|
||||
) {
|
||||
let lastKnownFileType = fileAbsolutePath.extension.flatMap { Xcode.filetype(extension: $0) }
|
||||
let xcLanguageSpecificationIdentifier = lastKnownFileType == "file.playground" ? "xcode.lang.swift" : nil
|
||||
let file = PBXFileReference(
|
||||
sourceTree: .group,
|
||||
name: name,
|
||||
lastKnownFileType: lastKnownFileType,
|
||||
path: fileRelativePath.pathString,
|
||||
xcLanguageSpecificationIdentifier: "xcode.lang.swift"
|
||||
xcLanguageSpecificationIdentifier: xcLanguageSpecificationIdentifier
|
||||
)
|
||||
pbxproj.add(object: file)
|
||||
toGroup.children.append(file)
|
||||
|
@ -604,35 +574,10 @@ class ProjectFileElements {
|
|||
path.extension == "lproj"
|
||||
}
|
||||
|
||||
func isPlayground(path: AbsolutePath) -> Bool {
|
||||
path.extension == "playground"
|
||||
}
|
||||
|
||||
func isVersionGroup(path: AbsolutePath) -> Bool {
|
||||
path.extension == "xcdatamodeld"
|
||||
}
|
||||
|
||||
func isFolderTypeFileSource(path: AbsolutePath) -> Bool {
|
||||
isXcassets(path: path) || isDocCArchive(path: path) || isScnassets(path: path)
|
||||
}
|
||||
|
||||
func isXcassets(path: AbsolutePath) -> Bool {
|
||||
path.extension == "xcassets"
|
||||
}
|
||||
|
||||
func isDocCArchive(path: AbsolutePath) -> Bool {
|
||||
path.extension == "docc"
|
||||
}
|
||||
|
||||
func isDocCTutorialFile(path: AbsolutePath) -> Bool {
|
||||
// Skip the initial DocC source directory
|
||||
!isDocCArchive(path: path) && path.pathString.contains(".docc")
|
||||
}
|
||||
|
||||
func isScnassets(path: AbsolutePath) -> Bool {
|
||||
path.extension == "scnassets"
|
||||
}
|
||||
|
||||
/// Normalizes a path. Some paths have no direct representation in Xcode,
|
||||
/// like localizable files. This method normalizes those and returns a project
|
||||
/// representable path.
|
||||
|
|
|
@ -8,6 +8,7 @@ public struct Target: Equatable, Hashable, Comparable, Codable {
|
|||
// in order to compile the documentation archive (including Tutorials, Articles, etc.)
|
||||
public static let validSourceExtensions: [String] = [
|
||||
"m", "swift", "mm", "cpp", "cc", "c", "d", "s", "intentdefinition", "xcmappingmodel", "metal", "mlmodel", "docc",
|
||||
"playground",
|
||||
]
|
||||
public static let validFolderExtensions: [String] = [
|
||||
"framework", "bundle", "app", "xcassets", "appiconset", "scnassets",
|
||||
|
|
|
@ -22,10 +22,27 @@ extension TuistGraph.CoreDataModel {
|
|||
} else if CoreDataVersionExtractor.isVersioned(at: modelPath) {
|
||||
return try CoreDataVersionExtractor.version(fromVersionFileAtPath: modelPath)
|
||||
} else {
|
||||
return modelPath.url.lastPathComponent.dropSuffix(".xcdatamodeld")
|
||||
return modelPath.basenameWithoutExt
|
||||
}
|
||||
}()
|
||||
|
||||
return CoreDataModel(path: modelPath, versions: versions, currentVersion: currentVersion)
|
||||
}
|
||||
}
|
||||
|
||||
extension TuistGraph.CoreDataModel {
|
||||
/// Maps a `.xcdatamodeld` package into a TuistGraph.CoreDataModel instance.
|
||||
/// - Parameters:
|
||||
/// - path: The path for a `.xcdatamodeld` package.
|
||||
static func from(path modelPath: AbsolutePath) throws -> TuistGraph.CoreDataModel {
|
||||
let versions = FileHandler.shared.glob(modelPath, glob: "*.xcdatamodel")
|
||||
let currentVersion: String = try {
|
||||
if CoreDataVersionExtractor.isVersioned(at: modelPath) {
|
||||
return try CoreDataVersionExtractor.version(fromVersionFileAtPath: modelPath)
|
||||
} else {
|
||||
return modelPath.basenameWithoutExt
|
||||
}
|
||||
}()
|
||||
return CoreDataModel(path: modelPath, versions: versions, currentVersion: currentVersion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,9 @@ extension TuistGraph.ResourceFileElement {
|
|||
excluded.formUnion(globs)
|
||||
}
|
||||
|
||||
let files = try FileHandler.shared.throwingGlob(AbsolutePath.root, glob: String(path.pathString.dropFirst()))
|
||||
let files = try FileHandler.shared
|
||||
.throwingGlob(.root, glob: String(path.pathString.dropFirst()))
|
||||
.filter { !$0.isInOpaqueDirectory }
|
||||
.filter(includeFiles)
|
||||
.filter { !excluded.contains($0) }
|
||||
|
||||
|
|
|
@ -57,11 +57,10 @@ extension TuistGraph.Target {
|
|||
generatorPaths: generatorPaths
|
||||
)
|
||||
|
||||
var (resources, resourcesPlaygrounds, invalidResourceGlobs) = try resourcesAndPlaygrounds(
|
||||
let (resources, resourcesPlaygrounds, resourcesCoreDatas, invalidResourceGlobs) = try resourcesAndOthers(
|
||||
manifest: manifest,
|
||||
generatorPaths: generatorPaths
|
||||
)
|
||||
resources = resourcesFlatteningBundles(resources: resources)
|
||||
|
||||
if !invalidResourceGlobs.isEmpty {
|
||||
throw TargetManifestMapperError.invalidResourcesGlob(targetName: name, invalidGlobs: invalidResourceGlobs)
|
||||
|
@ -79,7 +78,7 @@ extension TuistGraph.Target {
|
|||
|
||||
let coreDataModels = try manifest.coreDataModels.map {
|
||||
try TuistGraph.CoreDataModel.from(manifest: $0, generatorPaths: generatorPaths)
|
||||
}
|
||||
} + resourcesCoreDatas.map { try TuistGraph.CoreDataModel.from(path: $0) }
|
||||
|
||||
let scripts = try manifest.scripts.map {
|
||||
try TuistGraph.TargetScript.from(manifest: $0, generatorPaths: generatorPaths)
|
||||
|
@ -120,18 +119,24 @@ extension TuistGraph.Target {
|
|||
|
||||
// MARK: - Fileprivate
|
||||
|
||||
fileprivate static func resourcesAndPlaygrounds(
|
||||
fileprivate static func resourcesAndOthers(
|
||||
manifest: ProjectDescription.Target,
|
||||
generatorPaths: GeneratorPaths
|
||||
// swiftlint:disable:next large_tuple
|
||||
) throws -> (resources: [TuistGraph.ResourceFileElement], playgrounds: [AbsolutePath], invalidResourceGlobs: [InvalidGlob]) {
|
||||
) throws -> (
|
||||
resources: [TuistGraph.ResourceFileElement],
|
||||
playgrounds: [AbsolutePath],
|
||||
coreDataModels: [AbsolutePath],
|
||||
invalidResourceGlobs: [InvalidGlob]
|
||||
) {
|
||||
let resourceFilter = { (path: AbsolutePath) -> Bool in
|
||||
TuistGraph.Target.isResource(path: path)
|
||||
}
|
||||
|
||||
var invalidResourceGlobs: [InvalidGlob] = []
|
||||
var resourcesWithoutPlaygrounds: [TuistGraph.ResourceFileElement] = []
|
||||
var filteredResources: [TuistGraph.ResourceFileElement] = []
|
||||
var playgrounds: Set<AbsolutePath> = []
|
||||
var coreDataModels: Set<AbsolutePath> = []
|
||||
|
||||
let allResources = try (manifest.resources?.resources ?? []).flatMap { manifest -> [TuistGraph.ResourceFileElement] in
|
||||
do {
|
||||
|
@ -146,42 +151,29 @@ extension TuistGraph.Target {
|
|||
}
|
||||
}
|
||||
|
||||
allResources.forEach { fileElement in
|
||||
allResources
|
||||
.forEach { fileElement in
|
||||
switch fileElement {
|
||||
case .folderReference: resourcesWithoutPlaygrounds.append(fileElement)
|
||||
case .folderReference: filteredResources.append(fileElement)
|
||||
case let .file(path, _):
|
||||
if path.pathString.contains(".playground/") {
|
||||
playgrounds.insert(path.upToComponentMatching(extension: "playground"))
|
||||
if path.extension == "playground" {
|
||||
playgrounds.insert(path)
|
||||
} else if path.extension == "xcdatamodeld" {
|
||||
coreDataModels.insert(path)
|
||||
} else {
|
||||
resourcesWithoutPlaygrounds.append(fileElement)
|
||||
filteredResources.append(fileElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
resources: resourcesWithoutPlaygrounds,
|
||||
resources: filteredResources,
|
||||
playgrounds: Array(playgrounds),
|
||||
coreDataModels: Array(coreDataModels),
|
||||
invalidResourceGlobs: invalidResourceGlobs
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate static func resourcesFlatteningBundles(resources: [TuistGraph.ResourceFileElement])
|
||||
-> [TuistGraph.ResourceFileElement]
|
||||
{
|
||||
Array(resources.reduce(into: Set<TuistGraph.ResourceFileElement>()) { flattenedResources, resourceElement in
|
||||
switch resourceElement {
|
||||
case let .file(path, _):
|
||||
if path.pathString.contains(".bundle/") {
|
||||
flattenedResources.formUnion([.file(path: path.upToComponentMatching(extension: "bundle"))])
|
||||
} else {
|
||||
flattenedResources.formUnion([resourceElement])
|
||||
}
|
||||
case .folderReference:
|
||||
flattenedResources.formUnion([resourceElement])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fileprivate static func sourcesAndPlaygrounds(
|
||||
manifest: ProjectDescription.Target,
|
||||
targetName: String,
|
||||
|
@ -204,8 +196,8 @@ extension TuistGraph.Target {
|
|||
} ?? [])
|
||||
|
||||
allSources.forEach { sourceFile in
|
||||
if sourceFile.path.pathString.contains(".playground/") {
|
||||
playgrounds.insert(sourceFile.path.upToComponentMatching(extension: "playground"))
|
||||
if sourceFile.path.extension == "playground" {
|
||||
playgrounds.insert(sourceFile.path)
|
||||
} else {
|
||||
sourcesWithoutPlaygrounds.append(sourceFile)
|
||||
}
|
||||
|
|
|
@ -66,6 +66,31 @@ extension AbsolutePath {
|
|||
return UTTypeConformsTo(uti.takeRetainedValue(), kUTTypePackage)
|
||||
}
|
||||
|
||||
private static let opaqueDirectoriesExtensions: Set<String> = [
|
||||
"xcassets",
|
||||
"scnassets",
|
||||
"xcdatamodeld",
|
||||
"docc",
|
||||
"playground",
|
||||
"bundle",
|
||||
]
|
||||
|
||||
/// An opaque directory is a directory that should be treated like a file, therefor ignoring its content.
|
||||
/// I.e.: .xcassets, .xcdatamodeld, etc...
|
||||
/// This property returns true when a file is contained in such directory.
|
||||
public var isInOpaqueDirectory: Bool {
|
||||
var currentDirectory = parentDirectory
|
||||
while currentDirectory != .root {
|
||||
if let `extension` = currentDirectory.extension,
|
||||
Self.opaqueDirectoriesExtensions.contains(`extension`)
|
||||
{
|
||||
return true
|
||||
}
|
||||
currentDirectory = currentDirectory.parentDirectory
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// Returns the path with the last component removed. For example, given the path
|
||||
/// /test/path/to/file it returns /test/path/to
|
||||
///
|
||||
|
@ -99,24 +124,6 @@ extension AbsolutePath {
|
|||
return ancestorPath
|
||||
}
|
||||
|
||||
public func upToComponentMatching(regex: String) -> AbsolutePath {
|
||||
if isRoot { return self }
|
||||
if basename.range(of: regex, options: .regularExpression) == nil {
|
||||
return parentDirectory.upToComponentMatching(regex: regex)
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
public func upToComponentMatching(extension: String) -> AbsolutePath {
|
||||
if isRoot { return self }
|
||||
if self.extension == `extension` {
|
||||
return self
|
||||
} else {
|
||||
return parentDirectory.upToComponentMatching(extension: `extension`)
|
||||
}
|
||||
}
|
||||
|
||||
public var upToLastNonGlob: AbsolutePath {
|
||||
guard let index = components.firstIndex(where: { $0.isGlobComponent }) else {
|
||||
return self
|
||||
|
|
|
@ -170,7 +170,7 @@ final class BuildPhaseGeneratorTests: TuistUnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func test_generateSourcesBuildPhase_withDocCArchive_ArticleAndTutorial() throws {
|
||||
func test_generateSourcesBuildPhase_withDocCArchive() throws {
|
||||
// Given
|
||||
let target = PBXNativeTarget(name: "Test")
|
||||
let pbxproj = PBXProj()
|
||||
|
@ -179,10 +179,6 @@ final class BuildPhaseGeneratorTests: TuistUnitTestCase {
|
|||
let sources: [SourceFile] = [
|
||||
SourceFile(path: "/path/sources/Foo.swift", compilerFlags: nil),
|
||||
SourceFile(path: "/path/sources/Doc.docc", compilerFlags: nil),
|
||||
SourceFile(path: "/path/sources/Doc.docc/Articles/Article.md", compilerFlags: nil),
|
||||
SourceFile(path: "/path/sources/Doc.docc/Tutorials/Tutorials.md", compilerFlags: nil),
|
||||
SourceFile(path: "/path/sources/Doc.docc/Tutorials/Step-1.swift", compilerFlags: nil),
|
||||
SourceFile(path: "/path/sources/Doc.docc/Tutorials/Step-2.swift", compilerFlags: nil),
|
||||
]
|
||||
|
||||
let fileElements = createFileElements(for: sources.map(\.path))
|
||||
|
|
|
@ -163,7 +163,7 @@ final class ProjectFileElementsTests: TuistUnitTestCase {
|
|||
func test_addElement_xcassets() throws {
|
||||
// Given
|
||||
let element = GroupFileElement(
|
||||
path: "/path/myfolder/resources/assets.xcassets/foo/bar.png",
|
||||
path: "/path/myfolder/resources/assets.xcassets",
|
||||
group: .group(name: "Project")
|
||||
)
|
||||
|
||||
|
@ -207,7 +207,7 @@ final class ProjectFileElementsTests: TuistUnitTestCase {
|
|||
func test_addElement_scnassets() throws {
|
||||
// Given
|
||||
let element = GroupFileElement(
|
||||
path: "/path/myfolder/resources/assets.scnassets/foo.exr",
|
||||
path: "/path/myfolder/resources/assets.scnassets",
|
||||
group: .group(name: "Project")
|
||||
)
|
||||
|
||||
|
@ -226,42 +226,6 @@ final class ProjectFileElementsTests: TuistUnitTestCase {
|
|||
])
|
||||
}
|
||||
|
||||
func test_addElement_xcassets_and_scnassets_multiple_files() throws {
|
||||
// Given
|
||||
let resources = [
|
||||
"/path/myfolder/resources/assets.xcassets/foo/a.png",
|
||||
"/path/myfolder/resources/assets.xcassets/foo/abc/b.png",
|
||||
"/path/myfolder/resources/assets.xcassets/foo/def/c.png",
|
||||
"/path/myfolder/resources/assets.xcassets",
|
||||
"/path/myfolder/resources/assets.scnassets/foo.exr",
|
||||
"/path/myfolder/resources/assets.scnassets/bar.exr",
|
||||
"/path/myfolder/resources/assets.scnassets",
|
||||
]
|
||||
let elements = resources.map {
|
||||
GroupFileElement(
|
||||
path: AbsolutePath($0),
|
||||
group: .group(name: "Project")
|
||||
)
|
||||
}
|
||||
|
||||
// When
|
||||
try elements.forEach {
|
||||
try subject.generate(
|
||||
fileElement: $0,
|
||||
groups: groups,
|
||||
pbxproj: pbxproj,
|
||||
sourceRootPath: "/path"
|
||||
)
|
||||
}
|
||||
|
||||
// Then
|
||||
let projectGroup = groups.sortedMain.group(named: "Project")
|
||||
XCTAssertEqual(projectGroup?.flattenedChildren.sorted(), [
|
||||
"myfolder/resources/assets.scnassets",
|
||||
"myfolder/resources/assets.xcassets",
|
||||
])
|
||||
}
|
||||
|
||||
func test_addElement_lproj_multiple_files() throws {
|
||||
// Given
|
||||
let temporaryPath = try temporaryPath()
|
||||
|
@ -683,7 +647,7 @@ final class ProjectFileElementsTests: TuistUnitTestCase {
|
|||
pbxproj.add(object: group)
|
||||
|
||||
// When
|
||||
subject.addPlayground(
|
||||
subject.addFileElement(
|
||||
from: from,
|
||||
fileAbsolutePath: fileAbsolutePath,
|
||||
fileRelativePath: fileRelativePath,
|
||||
|
@ -768,11 +732,6 @@ final class ProjectFileElementsTests: TuistUnitTestCase {
|
|||
XCTAssertTrue(subject.isLocalized(path: path))
|
||||
}
|
||||
|
||||
func test_isPlayground() {
|
||||
let path = AbsolutePath("/path/to/MyPlayground.playground")
|
||||
XCTAssertTrue(subject.isPlayground(path: path))
|
||||
}
|
||||
|
||||
func test_isVersionGroup() {
|
||||
let path = AbsolutePath("/path/to/model.xcdatamodeld")
|
||||
XCTAssertTrue(subject.isVersionGroup(path: path))
|
||||
|
|
|
@ -35,7 +35,22 @@ final class TargetTests: TuistUnitTestCase {
|
|||
func test_validSourceExtensions() {
|
||||
XCTAssertEqual(
|
||||
Target.validSourceExtensions,
|
||||
["m", "swift", "mm", "cpp", "cc", "c", "d", "s", "intentdefinition", "xcmappingmodel", "metal", "mlmodel", "docc"]
|
||||
[
|
||||
"m",
|
||||
"swift",
|
||||
"mm",
|
||||
"cpp",
|
||||
"cc",
|
||||
"c",
|
||||
"d",
|
||||
"s",
|
||||
"intentdefinition",
|
||||
"xcmappingmodel",
|
||||
"metal",
|
||||
"mlmodel",
|
||||
"docc",
|
||||
"playground",
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -69,25 +69,27 @@ final class AbsolutePathExtrasTests: TuistUnitTestCase {
|
|||
)
|
||||
}
|
||||
|
||||
func test_upToComponentMatchingRegex() throws {
|
||||
// Given
|
||||
let path = AbsolutePath("/path/to/sources/Playground.playground/Content.swift")
|
||||
func test_isInOpaqueDirectory() throws {
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.bundle").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.xcassets").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.xcassets").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.scnassets").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.xcdatamodeld").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.docc").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.playground").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.bundle").isInOpaqueDirectory)
|
||||
|
||||
// When
|
||||
let got = path.upToComponentMatching(regex: ".+\\.playground")
|
||||
XCTAssertFalse(AbsolutePath("/").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.notopaque/file.notopaque").isInOpaqueDirectory)
|
||||
XCTAssertFalse(AbsolutePath("/test/directory.notopaque/directory.bundle").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.notopaque/directory.bundle/file.png").isInOpaqueDirectory)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(got, "/path/to/sources/Playground.playground")
|
||||
}
|
||||
|
||||
func test_upToComponentMatchingExtension() throws {
|
||||
// Given
|
||||
let path = AbsolutePath("/path/to/sources/Playground.playground/Content.swift")
|
||||
|
||||
// When
|
||||
let got = path.upToComponentMatching(extension: "playground")
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(got, "/path/to/sources/Playground.playground")
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.bundle/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.xcassets/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.xcassets/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.scnassets/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.xcdatamodeld/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.docc/file.png").isInOpaqueDirectory)
|
||||
XCTAssertTrue(AbsolutePath("/test/directory.playground/file.png").isInOpaqueDirectory)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ Feature: Tuist dependencies.
|
|||
Then I copy the fixture app_with_spm_dependencies into the working directory
|
||||
Then tuist fetches dependencies
|
||||
Then tuist generates the project
|
||||
Then tuist builds the scheme App from the project
|
||||
Then tuist builds the scheme App from the project with device "iPhone 8"
|
||||
|
||||
Scenario: The project is a sub project within a workspace with SPM Dependencies.swift (app_with_spm_dependencies)
|
||||
Given that tuist is available
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
require "xcodeproj"
|
||||
|
||||
Then(/^tuist builds the project$/) do
|
||||
system(@tuist, "build", "--path", @dir)
|
||||
|
@ -8,6 +9,25 @@ Then(/^tuist builds the scheme ([a-zA-Z\-]+) from the project$/) do |scheme|
|
|||
system(@tuist, "build", scheme, "--path", @dir)
|
||||
end
|
||||
|
||||
Then(/^tuist builds the scheme ([a-zA-Z\-]+) from the project with device "(.+)"$/) do |scheme, device|
|
||||
args = [
|
||||
"-scheme", scheme,
|
||||
"-sdk", "iphonesimulator",
|
||||
]
|
||||
if @workspace_path.nil?
|
||||
args.concat(["-project", @xcodeproj_path]) unless @xcodeproj_path.nil?
|
||||
else
|
||||
args.concat(["-workspace", @workspace_path]) unless @workspace_path.nil?
|
||||
end
|
||||
|
||||
args.concat(["-destination", "'name=#{device}'"])
|
||||
|
||||
args << "build"
|
||||
|
||||
xcodebuild(*args)
|
||||
end
|
||||
|
||||
|
||||
Then(%r{^tuist builds the scheme ([a-zA-Z\-]+) from the project at ([a-zA-Z/]+)$}) do |scheme, path|
|
||||
system(@tuist, "build", scheme, "--path", File.join(@dir, path))
|
||||
end
|
||||
|
|
|
@ -31,6 +31,7 @@ let project = Project(
|
|||
.external(name: "FirebaseAnalytics"),
|
||||
.external(name: "FirebaseDatabase"),
|
||||
.external(name: "FirebaseFirestore"),
|
||||
.external(name: "IterableSDK"),
|
||||
]
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,6 +6,7 @@ import FirebaseAnalytics
|
|||
import FirebaseCore
|
||||
import FirebaseDatabase
|
||||
import FirebaseFirestore
|
||||
import IterableSDK
|
||||
|
||||
public enum AppKit {
|
||||
public static func start() {
|
||||
|
@ -26,5 +27,7 @@ public enum AppKit {
|
|||
|
||||
// Use FirebaseFirestore to make sure it links fine
|
||||
_ = Firestore.firestore()
|
||||
|
||||
_ = IterableSDK.IterableAPI.sdkVersion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ let dependencies = Dependencies(
|
|||
.package(url: "https://github.com/facebook/facebook-ios-sdk", .upToNextMajor(from: "12.1.0")),
|
||||
.package(url: "https://github.com/firebase/firebase-ios-sdk", .upToNextMajor(from: "8.0.0")),
|
||||
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMinor(from: "0.22.0")),
|
||||
.package(url: "https://github.com/iterable/swift-sdk", .upToNextMajor(from: "6.0.0")),
|
||||
],
|
||||
platforms: [.iOS]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue