Skip to content

Commit

Permalink
Fix tuist init due to missing ProjectDescriptionHelpers (tuist#6792)
Browse files Browse the repository at this point in the history
  • Loading branch information
fortmarek authored Oct 2, 2024
1 parent 964a370 commit e057e62
Show file tree
Hide file tree
Showing 56 changed files with 626 additions and 393 deletions.
55 changes: 44 additions & 11 deletions Sources/TuistCore/Utils/RootDirectoryLocator.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
import FileSystem
import Foundation
import Mockable
import Path
import TuistSupport

enum RootDirectoryLocatorError: FatalError, Equatable {
/// Thrown when the root directory can't be located.
case rootDirectoryNotFound(AbsolutePath)

var type: ErrorType {
switch self {
case .rootDirectoryNotFound: return .abort
}
}

var description: String {
switch self {
case let .rootDirectoryNotFound(path):
return "Couldn't locate the root directory from path \(path.pathString). The root directory is the closest directory that contains a Tuist or a .git directory."
}
}
}

@Mockable
public protocol RootDirectoryLocating {
/// Given a path, it finds the root directory by traversing up the hierarchy.
Expand All @@ -12,34 +31,48 @@ public protocol RootDirectoryLocating {
/// - Directory containing a `Plugin.swift` manifest.
/// - Directory containing a `.git/` subdirectory.
///
func locate(from path: AbsolutePath) -> AbsolutePath?
func locate(from path: AbsolutePath) async throws -> AbsolutePath?
}

extension RootDirectoryLocating {
public func locate(from path: AbsolutePath) async throws -> AbsolutePath {
guard let rootDirectory = try await locate(from: path)
else { throw RootDirectoryLocatorError.rootDirectoryNotFound(path) }
return rootDirectory
}
}

public final class RootDirectoryLocator: RootDirectoryLocating {
private let fileHandler: FileHandling = FileHandler.shared
private let fileSystem: FileSysteming
/// This cache avoids having to traverse the directories hierarchy every time the locate method is called.
private let cache: ThreadSafe<[AbsolutePath: AbsolutePath]> = ThreadSafe([:])

public init() {}
public init(
fileSystem: FileSysteming = FileSystem()
) {
self.fileSystem = fileSystem
}

public func locate(from path: AbsolutePath) -> AbsolutePath? {
locate(from: path, source: path)
public func locate(from path: AbsolutePath) async throws -> AbsolutePath? {
try await locate(from: path, source: path)
}

private func locate(from path: AbsolutePath, source: AbsolutePath) -> AbsolutePath? {
if let cachedDirectory = cached(path: path) {
private func locate(from path: AbsolutePath, source: AbsolutePath) async throws -> AbsolutePath? {
if try await !fileSystem.exists(path, isDirectory: true) {
return try await locate(from: path.parentDirectory, source: source)
} else if let cachedDirectory = cached(path: path) {
return cachedDirectory
} else if fileHandler.exists(path.appending(component: Constants.tuistDirectoryName)) {
} else if try await fileSystem.exists(path.appending(component: Constants.tuistDirectoryName)) {
cache(rootDirectory: path, for: source)
return path
} else if fileHandler.exists(path.appending(component: "Plugin.swift")) {
} else if try await fileSystem.exists(path.appending(component: "Plugin.swift")) {
cache(rootDirectory: path, for: source)
return path
} else if fileHandler.isFolder(path.appending(component: ".git")) {
} else if try await fileSystem.exists(path.appending(component: ".git"), isDirectory: true) {
cache(rootDirectory: path, for: source)
return path
} else if !path.isRoot {
return locate(from: path.parentDirectory, source: source)
return try await locate(from: path.parentDirectory, source: source)
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/TuistGenerator/Linter/EnvironmentLinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class EnvironmentLinter: EnvironmentLinting {
public func lint(config: Config) async throws -> [LintingIssue] {
var issues = [LintingIssue]()

issues.append(contentsOf: try lintConfigPath(config: config))
issues.append(contentsOf: try await lintConfigPath(config: config))
issues.append(contentsOf: try await lintXcodeVersion(config: config))

return issues
Expand Down Expand Up @@ -51,9 +51,9 @@ public class EnvironmentLinter: EnvironmentLinting {
}
}

func lintConfigPath(config: Config) throws -> [LintingIssue] {
func lintConfigPath(config: Config) async throws -> [LintingIssue] {
guard let configPath = config.path,
let rootDirectoryPath = rootDirectoryLocator.locate(from: configPath)
let rootDirectoryPath = try await rootDirectoryLocator.locate(from: configPath)
else {
return []
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ public final class StaticXCFrameworkModuleMapGraphMapper: GraphMapping {
self.manifestFilesLocator = manifestFilesLocator
}

public func map(graph: Graph, environment: MapperEnvironment) throws -> (Graph, [SideEffectDescriptor], MapperEnvironment) {
guard let packageManifest = manifestFilesLocator.locatePackageManifest(at: graph.path)
public func map(
graph: Graph,
environment: MapperEnvironment
) async throws -> (Graph, [SideEffectDescriptor], MapperEnvironment) {
guard let packageManifest = try await manifestFilesLocator.locatePackageManifest(at: graph.path)
else { return (graph, [], environment) }
let derivedDirectory = packageManifest
.parentDirectory
Expand Down
10 changes: 5 additions & 5 deletions Sources/TuistKit/ProjectEditor/ProjectEditor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ final class ProjectEditor: ProjectEditing {
] + tuistIgnoreEntries

let projectDescriptionPath = try await resourceLocator.projectDescription()
let projectManifests = manifestFilesLocator.locateProjectManifests(
let projectManifests = try await manifestFilesLocator.locateProjectManifests(
at: editingPath,
excluding: pathsToExclude,
onlyCurrentDirectory: onlyCurrentDirectory
Expand All @@ -136,7 +136,7 @@ final class ProjectEditor: ProjectEditing {
let projectDescriptionHelpersBuilder = projectDescriptionHelpersBuilderFactory.projectDescriptionHelpersBuilder(
cacheDirectory: try cacheDirectoriesProvider.cacheDirectory(for: .projectDescriptionHelpers)
)
let packageManifestPath = manifestFilesLocator.locatePackageManifest(at: editingPath)
let packageManifestPath = try await manifestFilesLocator.locatePackageManifest(at: editingPath)

let helpers = try await helpersDirectoryLocator.locate(at: editingPath).map {
[
Expand All @@ -161,7 +161,7 @@ final class ProjectEditor: ProjectEditing {
FileHandler.shared.glob($0, glob: "**/*.stencil")
} ?? []

let editablePluginManifests = try locateEditablePluginManifests(
let editablePluginManifests = try await locateEditablePluginManifests(
at: editingPath,
excluding: pathsToExclude,
plugins: plugins,
Expand Down Expand Up @@ -215,12 +215,12 @@ final class ProjectEditor: ProjectEditing {
excluding: [String],
plugins: Plugins,
onlyCurrentDirectory: Bool
) throws -> [EditablePluginManifest] {
) async throws -> [EditablePluginManifest] {
let loadedEditablePluginManifests = try plugins.projectDescriptionHelpers
.filter { $0.location == .local }
.map { EditablePluginManifest(name: $0.name, path: try FileHandler.shared.resolveSymlinks($0.path.parentDirectory)) }

let localEditablePluginManifests = try manifestFilesLocator.locatePluginManifests(
let localEditablePluginManifests = try await manifestFilesLocator.locatePluginManifests(
at: path,
excluding: excluding,
onlyCurrentDirectory: onlyCurrentDirectory
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistKit/Services/CleanService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ final class CleanService {
FileHandler.shared.currentPath
}

let packageDirectory = manifestFilesLocator.locatePackageManifest(at: resolvedPath)?.parentDirectory
let packageDirectory = try await manifestFilesLocator.locatePackageManifest(at: resolvedPath)?.parentDirectory

for category in categories {
let directory: AbsolutePath?
Expand Down
10 changes: 3 additions & 7 deletions Sources/TuistKit/Services/InitService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,17 @@ class InitService {
private let templatesDirectoryLocator: TemplatesDirectoryLocating
private let templateGenerator: TemplateGenerating
private let templateGitLoader: TemplateGitLoading
private let tuistVersionLoader: TuistVersionLoading

init(
templateLoader: TemplateLoading = TemplateLoader(),
templatesDirectoryLocator: TemplatesDirectoryLocating = TemplatesDirectoryLocator(),
templateGenerator: TemplateGenerating = TemplateGenerator(),
templateGitLoader: TemplateGitLoading = TemplateGitLoader(),
tuistVersionLoader: TuistVersionLoading = TuistVersionLoader()
templateGitLoader: TemplateGitLoading = TemplateGitLoader()
) {
self.templateLoader = templateLoader
self.templatesDirectoryLocator = templatesDirectoryLocator
self.templateGenerator = templateGenerator
self.templateGitLoader = templateGitLoader
self.tuistVersionLoader = tuistVersionLoader
}

func loadTemplateOptions(
Expand Down Expand Up @@ -113,15 +110,14 @@ class InitService {
let path = try self.path(path)
let name = try self.name(name, path: path)
let templateName = templateName ?? "default"
let tuistVersion = try tuistVersionLoader.getVersion()
try verifyDirectoryIsEmpty(path: path)

if templateName.isGitURL {
try await templateGitLoader.loadTemplate(from: templateName, closure: { template in
let parsedAttributes = try self.parseAttributes(
name: name,
platform: platform,
tuistVersion: tuistVersion,
tuistVersion: Constants.version,
requiredTemplateOptions: requiredTemplateOptions,
optionalTemplateOptions: optionalTemplateOptions,
template: template
Expand All @@ -142,7 +138,7 @@ class InitService {
let parsedAttributes = try parseAttributes(
name: name,
platform: platform,
tuistVersion: tuistVersion,
tuistVersion: Constants.version,
requiredTemplateOptions: requiredTemplateOptions,
optionalTemplateOptions: optionalTemplateOptions,
template: template
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistKit/Services/InstallService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ final class InstallService {
}

private func fetchDependencies(path: AbsolutePath, update: Bool) async throws {
guard let packageManifestPath = manifestFilesLocator.locatePackageManifest(at: path)
guard let packageManifestPath = try await manifestFilesLocator.locatePackageManifest(at: path)
else {
return
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/TuistKit/Utils/ManifestGraphLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public final class ManifestGraphLoader: ManifestGraphLoading {
let packageSettings: TuistCore.PackageSettings?

// Load SPM graph only if is SPM Project only or the workspace is using external dependencies
if let packagePath = manifestFilesLocator.locatePackageManifest(at: path),
if let packagePath = try await manifestFilesLocator.locatePackageManifest(at: path),
isSPMProjectOnly || hasExternalDependencies
{
let loadedPackageSettings = try await packageSettingsLoader.loadPackageSettings(
Expand Down
20 changes: 0 additions & 20 deletions Sources/TuistKit/Utils/TuistVersionLoader.swift

This file was deleted.

15 changes: 10 additions & 5 deletions Sources/TuistLoader/Loaders/ConfigLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public protocol ConfigLoading {
func loadConfig(path: AbsolutePath) async throws -> TuistCore.Config

/// Locates the Config.swift manifest from the given directory.
func locateConfig(at: AbsolutePath) -> AbsolutePath?
func locateConfig(at: AbsolutePath) async throws -> AbsolutePath?
}

public final class ConfigLoader: ConfigLoading {
Expand All @@ -41,21 +41,26 @@ public final class ConfigLoader: ConfigLoading {
return cached
}

guard let configPath = locateConfig(at: path) else {
guard let configPath = try await locateConfig(at: path) else {
let config = TuistCore.Config.default
cachedConfigs[path] = config
return config
}

let manifest = try await manifestLoader.loadConfig(at: configPath.parentDirectory)
let config = try TuistCore.Config.from(manifest: manifest, at: configPath)
let rootDirectory: AbsolutePath = try await rootDirectoryLocator.locate(from: configPath)
let config = try await TuistCore.Config.from(
manifest: manifest,
rootDirectory: rootDirectory,
at: configPath
)
cachedConfigs[path] = config
return config
}

public func locateConfig(at path: AbsolutePath) -> AbsolutePath? {
public func locateConfig(at path: AbsolutePath) async throws -> AbsolutePath? {
// If the Config.swift file exists in the root Tuist/ directory, we load it from there
if let rootDirectoryPath = rootDirectoryLocator.locate(from: path) {
if let rootDirectoryPath = try await rootDirectoryLocator.locate(from: path) {
// swiftlint:disable:next force_try
let relativePath = try! RelativePath(validating: "\(Constants.tuistDirectoryName)/\(Manifest.config.fileName(path))")
let configPath = rootDirectoryPath.appending(relativePath)
Expand Down
29 changes: 23 additions & 6 deletions Sources/TuistLoader/Loaders/ManifestModelConverter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ public protocol ManifestModelConverting {
public final class ManifestModelConverter: ManifestModelConverting {
private let manifestLoader: ManifestLoading
private let resourceSynthesizerPathLocator: ResourceSynthesizerPathLocating
private let rootDirectoryLocator: RootDirectoryLocating

public convenience init() {
self.init(
manifestLoader: ManifestLoader()
manifestLoader: ManifestLoader(),
rootDirectoryLocator: RootDirectoryLocator()
)
}

Expand All @@ -34,16 +36,19 @@ public final class ManifestModelConverter: ManifestModelConverting {
) {
self.init(
manifestLoader: manifestLoader,
resourceSynthesizerPathLocator: ResourceSynthesizerPathLocator()
resourceSynthesizerPathLocator: ResourceSynthesizerPathLocator(),
rootDirectoryLocator: RootDirectoryLocator()
)
}

init(
manifestLoader: ManifestLoading,
resourceSynthesizerPathLocator: ResourceSynthesizerPathLocating = ResourceSynthesizerPathLocator()
resourceSynthesizerPathLocator: ResourceSynthesizerPathLocating = ResourceSynthesizerPathLocator(),
rootDirectoryLocator: RootDirectoryLocating
) {
self.manifestLoader = manifestLoader
self.resourceSynthesizerPathLocator = resourceSynthesizerPathLocator
self.rootDirectoryLocator = rootDirectoryLocator
}

public func convert(
Expand All @@ -53,7 +58,11 @@ public final class ManifestModelConverter: ManifestModelConverting {
externalDependencies: [String: [XcodeGraph.TargetDependency]],
isExternal: Bool
) async throws -> XcodeGraph.Project {
let generatorPaths = GeneratorPaths(manifestDirectory: path)
let rootDirectory: AbsolutePath = try await rootDirectoryLocator.locate(from: path)
let generatorPaths = GeneratorPaths(
manifestDirectory: path,
rootDirectory: rootDirectory
)
return try await XcodeGraph.Project.from(
manifest: manifest,
generatorPaths: generatorPaths,
Expand All @@ -68,7 +77,11 @@ public final class ManifestModelConverter: ManifestModelConverting {
manifest: ProjectDescription.Workspace,
path: AbsolutePath
) async throws -> XcodeGraph.Workspace {
let generatorPaths = GeneratorPaths(manifestDirectory: path)
let rootDirectory: AbsolutePath = try await rootDirectoryLocator.locate(from: path)
let generatorPaths = GeneratorPaths(
manifestDirectory: path,
rootDirectory: rootDirectory
)
let workspace = try await XcodeGraph.Workspace.from(
manifest: manifest,
path: path,
Expand All @@ -82,12 +95,16 @@ public final class ManifestModelConverter: ManifestModelConverting {
manifest: TuistLoader.DependenciesGraph,
path: AbsolutePath
) async throws -> XcodeGraph.DependenciesGraph {
let rootDirectory: AbsolutePath = try await rootDirectoryLocator.locate(from: path)
let externalDependencies: [String: [XcodeGraph.TargetDependency]] = try manifest.externalDependencies
.mapValues { targetDependencies in
try targetDependencies.flatMap { targetDependencyManifest in
try XcodeGraph.TargetDependency.from(
manifest: targetDependencyManifest,
generatorPaths: GeneratorPaths(manifestDirectory: path),
generatorPaths: GeneratorPaths(
manifestDirectory: path,
rootDirectory: rootDirectory
),
externalDependencies: [:] // externalDependencies manifest can't contain other external dependencies,
)
}
Expand Down
Loading

0 comments on commit e057e62

Please sign in to comment.