diff --git a/Sources/DependencyCalculator/DependencyGraph.swift b/Sources/DependencyCalculator/DependencyGraph.swift index 6ef3a78..5eb020e 100644 --- a/Sources/DependencyCalculator/DependencyGraph.swift +++ b/Sources/DependencyCalculator/DependencyGraph.swift @@ -6,6 +6,7 @@ import Foundation import Git import PathKit import SelectiveTestLogger +import SelectiveTestShell import Workspace import XcodeProj @@ -200,8 +201,14 @@ extension WorkspaceInfo { } == nil } + // SwiftPM6 locks build directory up when parsing multiple packages concurrently + let isSwiftVersion6Plus = try isSwiftVersion6Plus() + return Array(allPackages).concurrentMap { path in - try? PackageTargetMetadata.parse(at: path.parent()) + try? PackageTargetMetadata.parse( + at: path.parent(), + addingIgnoreLockOption: isSwiftVersion6Plus + ) }.compactMap { $0 }.reduce([PackageTargetMetadata]()) { partialResult, new in var result = partialResult result.append(contentsOf: new) @@ -347,4 +354,22 @@ extension WorkspaceInfo { dependencyStructure: DependencyGraph(dependsOn: dependsOn), candidateTestPlan: candidateTestPlan) } + + private static func isSwiftVersion6Plus() throws -> Bool { + guard let regex = try? NSRegularExpression(pattern: #"Apple Swift version (\d+)"#) else { + return false + } + + let versionString = try Shell.execOrFail("swift --version") + let range = NSRange(versionString.startIndex.. 5 + { + return true + } else { + return false + } + } } diff --git a/Sources/DependencyCalculator/PackageMetadata.swift b/Sources/DependencyCalculator/PackageMetadata.swift index 61e352b..a6c667c 100644 --- a/Sources/DependencyCalculator/PackageMetadata.swift +++ b/Sources/DependencyCalculator/PackageMetadata.swift @@ -16,9 +16,17 @@ struct PackageTargetMetadata { let testTarget: Bool // TODO: Split in several methods - static func parse(at path: Path) throws -> [PackageTargetMetadata] { - // NB: Flag `--disable-sandbox` is required to allow running SPM from an SPM plugin - let manifest = try Shell.execOrFail("cd \(path) && swift package dump-package --disable-sandbox").trimmingCharacters(in: .newlines) + static func parse(at path: Path, addingIgnoreLockOption: Bool = false) throws -> [PackageTargetMetadata] { + // NB: + // - Flag `--disable-sandbox` is required to allow running SPM from an SPM plugin + // - Flag `--ignore-lock` is required to avoid locking the package build directory when parsing is done concurrently (Swift 6). + var flags = ["--disable-sandbox"] + if addingIgnoreLockOption { + flags.append("--ignore-lock") + } + + let manifest = try Shell.execOrFail("cd \(path) && swift package dump-package \(flags.joined(separator: " "))") + .trimmingCharacters(in: .newlines) guard let manifestData = manifest.data(using: .utf8), let manifestJson = try JSONSerialization.jsonObject(with: manifestData, options: []) as? [String: Any], let targets = manifestJson["targets"] as? [[String: Any]]