Skip to content

Commit 670cd69

Browse files
committed
store suggestion info in output folder
1 parent 38154b8 commit 670cd69

1 file changed

Lines changed: 98 additions & 1 deletion

File tree

Core/Sources/HostApp/Benchmark/Domain/Manager/BenchmarkManager.swift

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import CopilotForXcodeKit
1414
import BuiltinExtension
1515
import GitHubCopilotService
1616

17+
import Combine
18+
19+
1720
protocol BenchmarkManager {
1821

1922
}
@@ -43,9 +46,10 @@ class RealtimeSuggestionControllerBenchmarkManager: BenchmarkManager {
4346

4447
func getCodeSuggestions(at benchmarkDirectory: BenchmarkDirectory) async throws {
4548
let taskPaths: [URL] = getTaskFolders(in: benchmarkDirectory.url)
46-
for taskPath in taskPaths.prefix(1) {
49+
for (index, taskPath) in taskPaths.prefix(1).enumerated() {
4750
if let suggestion = await getCodeSuggestionFromService(at: taskPath, from: benchmarkDirectory.url) {
4851
await applyCodeSuggestion(suggestion: suggestion.suggestion, at: suggestion.fileURL)
52+
await storeContentInOutputDirectory(suggestion, for: index+1)
4953
}
5054

5155
}
@@ -135,6 +139,40 @@ class RealtimeSuggestionControllerBenchmarkManager: BenchmarkManager {
135139
}
136140
}
137141

142+
func storeContentInOutputDirectory(_ suggestion: SuggestionResponse, for taskNumber: Int) async {
143+
guard let outputDirPath = await benchmarkSettingsRepository.outputDirectory.firstValue() else {
144+
print("Could not retrieve output directory.")
145+
return
146+
}
147+
let fileManager = FileManager.default
148+
149+
let resolvedOutputDirPath = outputDirPath.replacingOccurrences(of: "~", with: fileManager.homeDirectoryForCurrentUser.path)
150+
let outputDir = URL(fileURLWithPath: resolvedOutputDirPath)
151+
152+
var isDirectory: ObjCBool = false
153+
if !fileManager.fileExists(atPath: outputDir.path, isDirectory: &isDirectory) || !isDirectory.boolValue {
154+
do {
155+
try fileManager.createDirectory(at: outputDir, withIntermediateDirectories: true, attributes: nil)
156+
} catch {
157+
print("Failed to create output directory:", error)
158+
return
159+
}
160+
}
161+
162+
let timestamp = ISO8601DateFormatter().string(from: Date())
163+
let reformattedTimestamp = timestamp.replacingOccurrences(of: ":", with: "-")
164+
let outputFileURL = outputDir.appendingPathComponent("Task-\(taskNumber)-\(reformattedTimestamp).json")
165+
166+
do {
167+
let dto = suggestion.toStoredDTO(timestamp: timestamp)
168+
let data = try JSONEncoder().encode(dto)
169+
try data.write(to: outputFileURL)
170+
print("Stored suggestion at: \(outputFileURL.path)")
171+
} catch {
172+
print("Failed to write suggestion file:", error)
173+
}
174+
}
175+
138176
func readMetadata(at taskFolder: URL) -> MetadataDTO? {
139177
let metadataURL = taskFolder.appendingPathComponent("metadata.json")
140178
do {
@@ -272,3 +310,62 @@ struct SuggestionResponse {
272310
let suggestion: SuggestionBasic.CodeSuggestion
273311
let fileURL: URL
274312
}
313+
314+
315+
extension AnyPublisher where Failure == Never {
316+
/// Awaits the first emitted value of the publisher (only for Failure == Never)
317+
func firstValue() async -> Output? {
318+
await withCheckedContinuation { continuation in
319+
var cancellable: AnyCancellable?
320+
cancellable = self.first().sink { value in
321+
continuation.resume(returning: value)
322+
cancellable?.cancel()
323+
}
324+
}
325+
}
326+
}
327+
328+
329+
struct StoredSuggestionDTO: Codable {
330+
let fileURL: String
331+
let id: String
332+
let suggestionText: String
333+
let position: CursorPositionDTO
334+
let range: CursorRangeDTO
335+
let createdAt: String
336+
337+
struct CursorPositionDTO: Codable {
338+
let line: Int
339+
let character: Int
340+
}
341+
342+
struct CursorRangeDTO: Codable {
343+
let start: CursorPositionDTO
344+
let end: CursorPositionDTO
345+
}
346+
}
347+
348+
extension SuggestionResponse {
349+
func toStoredDTO(timestamp: String) -> StoredSuggestionDTO {
350+
StoredSuggestionDTO(
351+
fileURL: fileURL.path,
352+
id: suggestion.id,
353+
suggestionText: suggestion.text,
354+
position: .init(
355+
line: suggestion.position.line,
356+
character: suggestion.position.character
357+
),
358+
range: .init(
359+
start: .init(
360+
line: suggestion.range.start.line,
361+
character: suggestion.range.start.character
362+
),
363+
end: .init(
364+
line: suggestion.range.end.line,
365+
character: suggestion.range.end.character
366+
)
367+
),
368+
createdAt: timestamp
369+
)
370+
}
371+
}

0 commit comments

Comments
 (0)