Fix missing target dependencies

This commit is contained in:
Pedro Piñera 2018-08-05 17:21:26 +02:00
parent 30021ad864
commit 84595c7025
9 changed files with 44 additions and 103 deletions

View File

@ -9,6 +9,10 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
- Install command https://github.com/tuist/tuist/pull/83 by @pepibumur.
- `--help-env` command to tuistenv by @pepibumur.
### Fixed
- Fix missing target dependencies by @pepibumur.
## 0.1.0
### Added

View File

@ -5,7 +5,7 @@ import Foundation
public class Workspace: Codable {
enum CodingKeys: String, CodingKey {
case name
case projects = "project"
case projects
}
public let name: String

View File

@ -10,6 +10,6 @@ public class Constants {
public struct Manifest {
public static let project = "Project.swift"
public static let workspace = "Woskspace.swift"
public static let workspace = "Workspace.swift"
}
}

View File

@ -3,19 +3,7 @@ import Foundation
import TuistCore
import xcodeproj
/// Interface for targets generation.
protocol TargetGenerating: AnyObject {
/// Generates the manifests target.
///
/// - Parameters:
/// - project: Project spec.
/// - pbxproj: PBXProj instance from the generated Xcode project.
/// - pbxProject: PBXProject instance from the generated project.
/// - groups: Project groups.
/// - sourceRootPath: Path to the folder that contains the project that is getting generated.
/// - context: generation context.
/// - options: Generation options.
/// - Throws: an error if the generation fails.
func generateManifestsTarget(project: Project,
pbxproj: PBXProj,
pbxProject: PBXProject,
@ -24,20 +12,6 @@ protocol TargetGenerating: AnyObject {
context: GeneratorContexting,
options: GenerationOptions) throws
/// Generates a native target.
///
/// - Parameters:
/// - target: Target spec.
/// - objects: Xcode project objects.
/// - pbxProject: PBXProject instance from the generated project.
/// - groups: Project groups.
/// - fileElements: Project file elements.
/// - sourceRootPath: Path to the folder that contains the project that is getting generated.
/// - context: generation context.
/// - path: Path to the folder that contains the project manifest.
/// - sourceRootPath: Path to the folder that contains the Xcode project that is generated.
/// - options: Generation options.
/// - Returns: native target.
func generateTarget(target targetSpec: Target,
objects: PBXObjects,
pbxProject: PBXProject,
@ -48,45 +22,24 @@ protocol TargetGenerating: AnyObject {
sourceRootPath: AbsolutePath,
options: GenerationOptions) throws -> PBXNativeTarget
/// Generates the targets dependencies.
///
/// - Parameters:
/// - path: path to the folder where the project manifest is.
/// - targets: project targets specs.
/// - nativeTargets: generated native targes in the Xcode project.
/// - objects: Xcode project objects.
/// - graph: dependencies graph.
/// - Throws: an error if it fails generating the target dependencies.
func generateTargetDependencies(path: AbsolutePath,
targets: [Target],
nativeTargets: [String: PBXNativeTarget],
graph: Graphing) throws
}
/// Target generator.
final class TargetGenerator: TargetGenerating {
/// Config generator.
// MARK: - Attributes
let configGenerator: ConfigGenerating
/// Build phase generator.
let buildPhaseGenerator: BuildPhaseGenerating
/// Link generator.
let linkGenerator: LinkGenerating
/// File generator.
let fileGenerator: FileGenerating
/// Module loader.
let moduleLoader: GraphModuleLoading
/// Initializes the target generator with its attributes.
///
/// - Parameters:
/// - configGenerator: config generator.
/// - fileGenerator: file generator.
/// - buildPhaseGenerator: build phase generator.
/// - linkGenerator: link generator.
// MARK: - Init
init(configGenerator: ConfigGenerating = ConfigGenerator(),
fileGenerator: FileGenerating = FileGenerator(),
buildPhaseGenerator: BuildPhaseGenerating = BuildPhaseGenerator(),
@ -99,16 +52,8 @@ final class TargetGenerator: TargetGenerating {
self.linkGenerator = linkGenerator
}
/// Generates the manifests target.
///
/// - Parameters:
/// - project: Project spec.
/// - pbxproj: PBXProj instance from the generated Xcode project.
/// - pbxProject: PBXProject instance from the generated project.
/// - groups: Project groups.
/// - sourceRootPath: Path to the folder that contains the project that is getting generated.
/// - context: generation context.
/// - options: generation options.
// MARK: - TargetGenerating
func generateManifestsTarget(project: Project,
pbxproj: PBXProj,
pbxProject: PBXProject,
@ -158,20 +103,6 @@ final class TargetGenerator: TargetGenerating {
pbxProject.targetsReferences.append(targetReference)
}
/// Generates a native target.
///
/// - Parameters:
/// - target: Target spec.
/// - objects: Xcode project objects.
/// - pbxProject: PBXProject instance from the generated project.
/// - groups: Project groups.
/// - fileElements: Project file elements.
/// - sourceRootPath: Path to the folder that contains the project that is getting generated.
/// - context: generation context.
/// - path: Path to the folder that contains the project manifest.
/// - sourceRootPath: path to the folder where the Xcode project is generated.
/// - options: Generation options.
/// - Returns: native target.
func generateTarget(target: Target,
objects: PBXObjects,
pbxProject: PBXProject,
@ -222,15 +153,6 @@ final class TargetGenerator: TargetGenerating {
return pbxTarget
}
/// Generates the targets dependencies.
///
/// - Parameters:
/// - path: path to the folder where the project manifest is.
/// - targets: project targets specs.
/// - nativeTargets: generated native targes in the Xcode project.
/// - objects: Xcode project objects.
/// - graph: dependencies graph.
/// - Throws: an error if it fails generating the target dependencies
func generateTargetDependencies(path: AbsolutePath,
targets: [Target],
nativeTargets: [String: PBXNativeTarget],

View File

@ -92,15 +92,14 @@ class Graph: Graphing {
targetNode.dependencies.forEach({ dependencies.insert($0) })
targetNode.dependencies.compactMap({ $0 as? TargetNode }).forEach(add)
}
if let target = cache.targetNodes[path]?[name] {
add(target)
if let targetNode = self.targetNode(path: path, name: name) {
add(targetNode)
}
return dependencies
}
func targetDependencies(path: AbsolutePath, name: String) -> [String] {
guard let targetNodes = cache.targetNodes[path] else { return [] }
guard let targetNode = targetNodes[name] else { return [] }
guard let targetNode = self.targetNode(path: path, name: name) else { return [] }
return targetNode.dependencies
.compactMap({ $0 as? TargetNode })
.filter({ $0.path == path })
@ -108,8 +107,7 @@ class Graph: Graphing {
}
func linkableDependencies(path: AbsolutePath, name: String) throws -> [DependencyReference] {
guard let targetNodes = cache.targetNodes[path] else { return [] }
guard let targetNode = targetNodes[name] else { return [] }
guard let targetNode = self.targetNode(path: path, name: name) else { return [] }
var references: [DependencyReference] = []
@ -136,8 +134,7 @@ class Graph: Graphing {
}
func librariesPublicHeadersFolders(path: AbsolutePath, name: String) -> [AbsolutePath] {
guard let targetNodes = cache.targetNodes[path] else { return [] }
guard let targetNode = targetNodes[name] else { return [] }
guard let targetNode = self.targetNode(path: path, name: name) else { return [] }
return targetNode
.dependencies
.compactMap({ $0 as? LibraryNode })
@ -147,8 +144,7 @@ class Graph: Graphing {
func embeddableFrameworks(path: AbsolutePath,
name: String,
shell: Shelling) throws -> [DependencyReference] {
guard let targetNodes = cache.targetNodes[path] else { return [] }
guard let targetNode = targetNodes[name] else { return [] }
guard let targetNode = self.targetNode(path: path, name: name) else { return [] }
let validProducts: [Product] = [
.app,
@ -188,4 +184,16 @@ class Graph: Graphing {
}))
return references
}
// MARK: - Fileprivate
fileprivate func targetNode(path: AbsolutePath, name: String) -> TargetNode? {
if let targetNode = self.entryNodes.compactMap({ $0 as? TargetNode }).first(where: {
$0.path == path && $0.target.name == name
}) {
return targetNode
}
guard let targetNodes = cache.targetNodes[path] else { return nil }
return targetNodes[name]
}
}

View File

@ -42,7 +42,7 @@ class GraphLoader: GraphLoading {
fileprivate func loadProject(path: AbsolutePath) throws -> Graph {
let cache = GraphLoaderCache()
let graphCircularDetector = GraphCircularDetector()
let project = try Project.at(path, cache: cache)
let project = try Project.at(path, cache: cache, graphCircularDetector: graphCircularDetector)
let entryNodes: [GraphNode] = try project.targets.map({ $0.name }).map { targetName in
return try TargetNode.read(name: targetName, path: path, cache: cache, graphCircularDetector: graphCircularDetector)
}
@ -57,7 +57,7 @@ class GraphLoader: GraphLoading {
let graphCircularDetector = GraphCircularDetector()
let workspace = try Workspace.at(path)
let projects = try workspace.projects.map { (projectPath) -> (AbsolutePath, Project) in
return try (projectPath, Project.at(projectPath, cache: cache))
return try (projectPath, Project.at(projectPath, cache: cache, graphCircularDetector: graphCircularDetector))
}
let entryNodes = try projects.flatMap { (project) -> [TargetNode] in
return try project.1.targets.map({ $0.name }).map { targetName in

View File

@ -53,7 +53,7 @@ class TargetNode: GraphNode {
cache: GraphLoaderCaching,
graphCircularDetector: GraphCircularDetecting) throws -> TargetNode {
if let targetNode = cache.targetNode(path, name: name) { return targetNode }
let project = try Project.at(path, cache: cache)
let project = try Project.at(path, cache: cache, graphCircularDetector: graphCircularDetector)
guard let target = project.targets.first(where: { $0.name == name }) else {
throw GraphLoadingError.targetNotFound(name, path)

View File

@ -25,17 +25,24 @@ class Project: Equatable {
// MARK: - Init
static func at(_ path: AbsolutePath, cache: GraphLoaderCaching) throws -> Project {
static func at(_ path: AbsolutePath, cache: GraphLoaderCaching, graphCircularDetector: GraphCircularDetecting) throws -> Project {
if let project = cache.project(path) {
return project
} else {
let project = try Project(path: path)
let project = try Project(path: path, cache: cache)
cache.add(project: project)
for target in project.targets {
if cache.targetNode(path, name: target.name) != nil { continue }
_ = try TargetNode.read(name: target.name, path: path, cache: cache, graphCircularDetector: graphCircularDetector)
}
return project
}
}
init(path: AbsolutePath,
cache _: GraphLoaderCaching,
fileHandler: FileHandling = FileHandler(),
manifestLoader: GraphManifestLoading = GraphManifestLoader()) throws {
let projectPath = path.appending(component: Constants.Manifest.project)

View File

@ -5,7 +5,7 @@ import XCTest
final class WorkspaceTests: XCTestCase {
func test_toJSON() {
let subject = Workspace(name: "name", projects: ["/path/to/project"])
let expected = "{\"name\": \"name\", \"project\": [\"/path/to/project\"]}"
let expected = "{\"name\": \"name\", \"projects\": [\"/path/to/project\"]}"
assertCodableEqualToJson(subject, expected)
}
}