Collapse nested Java source candidates
This commit is contained in:
parent
ba6edf6cc4
commit
6e728724bb
@ -684,6 +684,7 @@ enum JavaContentScanner {
|
|||||||
var candidatesByID: [String: SourceCandidate] = [:]
|
var candidatesByID: [String: SourceCandidate] = [:]
|
||||||
for root in roots {
|
for root in roots {
|
||||||
let candidateFolders = boundedCandidateFolders(from: root, maxDepth: 4, maxFolderCount: 600, fileManager: fileManager)
|
let candidateFolders = boundedCandidateFolders(from: root, maxDepth: 4, maxFolderCount: 600, fileManager: fileManager)
|
||||||
|
var candidatesForRoot: [SourceCandidate] = []
|
||||||
for folderURL in candidateFolders {
|
for folderURL in candidateFolders {
|
||||||
guard let probe = probeLocalFolder(folderURL, providerID: providerID) else {
|
guard let probe = probeLocalFolder(folderURL, providerID: providerID) else {
|
||||||
continue
|
continue
|
||||||
@ -699,6 +700,14 @@ enum JavaContentScanner {
|
|||||||
detectedKinds: probe.detectedKinds
|
detectedKinds: probe.detectedKinds
|
||||||
)
|
)
|
||||||
|
|
||||||
|
candidatesForRoot.append(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
for candidate in collapsedCandidates(
|
||||||
|
candidatesForRoot,
|
||||||
|
under: root,
|
||||||
|
providerID: providerID
|
||||||
|
) {
|
||||||
if let existingCandidate = candidatesByID[candidate.id],
|
if let existingCandidate = candidatesByID[candidate.id],
|
||||||
existingCandidate.confidence >= candidate.confidence {
|
existingCandidate.confidence >= candidate.confidence {
|
||||||
continue
|
continue
|
||||||
@ -938,6 +947,40 @@ enum JavaContentScanner {
|
|||||||
return candidates
|
return candidates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonisolated private static func collapsedCandidates(
|
||||||
|
_ candidates: [SourceCandidate],
|
||||||
|
under root: URL,
|
||||||
|
providerID: PlatformProviderID
|
||||||
|
) -> [SourceCandidate] {
|
||||||
|
let uniqueCandidates = Dictionary(grouping: candidates, by: \.sourceRootURL).compactMap { _, groupedCandidates in
|
||||||
|
groupedCandidates.max { lhs, rhs in
|
||||||
|
lhs.confidence < rhs.confidence
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard uniqueCandidates.count > 1 else {
|
||||||
|
return uniqueCandidates
|
||||||
|
}
|
||||||
|
|
||||||
|
let detectedKinds = uniqueCandidates.reduce(into: Set<MinecraftContentKind>()) { result, candidate in
|
||||||
|
result.formUnion(candidate.detectedKinds)
|
||||||
|
}
|
||||||
|
let confidence = uniqueCandidates.map(\.confidence).max() ?? .medium
|
||||||
|
let standardizedRoot = root.standardizedFileURL
|
||||||
|
|
||||||
|
return [
|
||||||
|
SourceCandidate(
|
||||||
|
providerID: providerID,
|
||||||
|
edition: .java,
|
||||||
|
sourceRootURL: standardizedRoot,
|
||||||
|
displayName: standardizedRoot.lastPathComponent,
|
||||||
|
confidence: confidence,
|
||||||
|
reason: "Found multiple Java sources under \(standardizedRoot.lastPathComponent)",
|
||||||
|
detectedKinds: detectedKinds
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
nonisolated private static func javaProbeScore(for url: URL, fileManager: FileManager) -> (value: Int, kinds: Set<MinecraftContentKind>) {
|
nonisolated private static func javaProbeScore(for url: URL, fileManager: FileManager) -> (value: Int, kinds: Set<MinecraftContentKind>) {
|
||||||
var score = 0
|
var score = 0
|
||||||
var kinds = Set<MinecraftContentKind>()
|
var kinds = Set<MinecraftContentKind>()
|
||||||
|
|||||||
@ -359,6 +359,32 @@ struct World_Manager_for_MinecraftTests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func javaProviderCollapsesNestedSourceCandidatesToSearchRoot() async throws {
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
let workingURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||||
|
let firstInstanceURL = workingURL.appendingPathComponent("a/b/c", isDirectory: true)
|
||||||
|
let secondInstanceURL = workingURL.appendingPathComponent("a/e/f", isDirectory: true)
|
||||||
|
defer { try? fileManager.removeItem(at: workingURL) }
|
||||||
|
|
||||||
|
for instanceURL in [firstInstanceURL, secondInstanceURL] {
|
||||||
|
try fileManager.createDirectory(
|
||||||
|
at: instanceURL.appendingPathComponent("mods", isDirectory: true),
|
||||||
|
withIntermediateDirectories: true
|
||||||
|
)
|
||||||
|
try Data("jar".utf8).write(to: instanceURL.appendingPathComponent("mods/ExampleMod.jar"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let candidates = JavaContentScanner.discoverSourceCandidates(
|
||||||
|
providerID: JavaLocalFolderSourceAccess().accessorIdentifier,
|
||||||
|
searchRoots: [workingURL]
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(candidates.count == 1)
|
||||||
|
#expect(candidates.first?.sourceRootURL == workingURL.standardizedFileURL)
|
||||||
|
#expect(candidates.first?.displayName == workingURL.lastPathComponent)
|
||||||
|
#expect(candidates.first?.detectedKinds.contains(.mod) == true)
|
||||||
|
}
|
||||||
|
|
||||||
@Test func sourceLibraryAddSourceResolvesJavaWrapperFolder() async throws {
|
@Test func sourceLibraryAddSourceResolvesJavaWrapperFolder() async throws {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let rootURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
let rootURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user