Skip to content

Commit 44e3285

Browse files
authored
Write a JSON report after parsing targets (#133)
1 parent 2a41a5b commit 44e3285

File tree

6 files changed

+96
-23
lines changed

6 files changed

+96
-23
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2025 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import Foundation
21+
22+
/// A report containing all parsed targets from the build graph.
23+
/// Written as JSON after buildTargets completes.
24+
struct BazelTargetGraphReport: Codable, Equatable {
25+
26+
struct TopLevelTarget: Codable, Equatable {
27+
let label: String
28+
let ruleType: String
29+
let platform: String
30+
let minimumOsVersion: String
31+
let cpuArch: String
32+
let isTest: Bool
33+
}
34+
35+
struct DependencyTarget: Codable, Equatable {
36+
let label: String
37+
let parents: [String]
38+
}
39+
40+
let topLevelTargets: [TopLevelTarget]
41+
let dependencyTargets: [DependencyTarget]
42+
}

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetQuerierParser.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ final class BazelTargetQuerierParserImpl: BazelTargetQuerierParser {
165165
throw BazelTargetQuerierParserError.noTopLevelTargets(supportedTopLevelRuleTypes)
166166
}
167167

168+
logger.logFullObjectInMultipleLogMessages(level: .info, header: "Top-level targets", String(topLevelTargets.map { $0.0.rule.name }.joined(separator: ", ")))
169+
168170
// Start by pre-processing all of the provided source files into a map for quick lookup.
169171
var srcToUriMap: [String: URI] = [:]
170172
for target in allSrcs {
@@ -320,7 +322,6 @@ final class BazelTargetQuerierParserImpl: BazelTargetQuerierParser {
320322
var bspURIsToBazelLabelsMap: [URI: String] = [:]
321323
var bspURIsToSrcsMap: [URI: SourcesItem] = [:]
322324
var srcToBspURIsMap: [URI: [URI]] = [:]
323-
var availableBazelLabels: Set<String> = []
324325
var topLevelLabelToRuleMap: [String: TopLevelRuleType] = [:]
325326
for dependencyTargetInfo in buildTargets {
326327
let target = dependencyTargetInfo.value.0
@@ -332,7 +333,6 @@ final class BazelTargetQuerierParserImpl: BazelTargetQuerierParser {
332333
let uri = target.id.uri
333334
bspURIsToBazelLabelsMap[uri] = displayName
334335
bspURIsToSrcsMap[uri] = sourcesItem
335-
availableBazelLabels.insert(displayName)
336336
for src in sourcesItem.sources {
337337
srcToBspURIsMap[src.uri, default: []].append(uri)
338338
}
@@ -348,7 +348,6 @@ final class BazelTargetQuerierParserImpl: BazelTargetQuerierParser {
348348
bspURIsToBazelLabelsMap: bspURIsToBazelLabelsMap,
349349
bspURIsToSrcsMap: bspURIsToSrcsMap,
350350
srcToBspURIsMap: srcToBspURIsMap,
351-
availableBazelLabels: availableBazelLabels,
352351
topLevelLabelToRuleMap: topLevelLabelToRuleMap,
353352
bazelLabelToParentsMap: bazelLabelToParentsMap
354353
)

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetStore.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
7777
private let supportedDependencyRuleTypes: [DependencyRuleType]
7878
private let compileMnemonicsToFilter: [String]
7979
private let topLevelMnemonicsToFilter: [String]
80+
private let reportQueue = DispatchQueue(label: "com.spotify.sourcekit-bazel-bsp.bazel-target-store.report-queue")
8081

8182
private var cachedTargets: [BuildTarget]? = nil
8283
private var aqueryResult: ProcessedAqueryResult? = nil
@@ -217,6 +218,13 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
217218
let result = cqueryResult.buildTargets
218219
cachedTargets = result
219220

221+
reportQueue.async { [weak self] in
222+
guard let self = self else { return }
223+
let outputPath = self.initializedConfig.outputPath
224+
let fileName = "sourcekit-bazel-bsp-graph.json"
225+
self.writeReport(toPath: outputPath + "/" + fileName)
226+
}
227+
220228
return result
221229
}
222230

@@ -227,3 +235,47 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
227235
cqueryResult = nil
228236
}
229237
}
238+
239+
extension BazelTargetStoreImpl {
240+
private func writeReport(toPath path: String) {
241+
let encoder = JSONEncoder()
242+
encoder.outputFormatting = .prettyPrinted
243+
do {
244+
let report = try generateGraphReport()
245+
let json = try encoder.encode(report)
246+
try json.write(to: URL(fileURLWithPath: path), options: .atomic)
247+
logger.info("Graph report written to \(path, privacy: .public)")
248+
} catch {
249+
logger.error("Failed to write graph report: \(error.localizedDescription, privacy: .public)")
250+
}
251+
}
252+
253+
private func generateGraphReport() throws -> BazelTargetGraphReport {
254+
logger.info("Generating graph report")
255+
var reportTopLevel: [BazelTargetGraphReport.TopLevelTarget] = []
256+
let topLevelTargets = cqueryResult?.topLevelTargets ?? []
257+
for (label, ruleType) in topLevelTargets {
258+
let topLevelConfig = try topLevelConfigInfo(forBazelLabel: label)
259+
reportTopLevel.append(
260+
.init(
261+
label: label,
262+
ruleType: ruleType.rawValue,
263+
platform: topLevelConfig.platform,
264+
minimumOsVersion: topLevelConfig.minimumOsVersion,
265+
cpuArch: topLevelConfig.cpuArch,
266+
isTest: ruleType.testBundleRule != nil
267+
)
268+
)
269+
}
270+
var reportDependencies: [BazelTargetGraphReport.DependencyTarget] = []
271+
let dependencyTargets = cqueryResult?.buildTargets.compactMap { $0.displayName } ?? []
272+
for label in dependencyTargets {
273+
let parents = try bazelLabelToParents(forBazelLabel: label)
274+
reportDependencies.append(.init(label: label, parents: parents))
275+
}
276+
return BazelTargetGraphReport(
277+
topLevelTargets: reportTopLevel,
278+
dependencyTargets: reportDependencies
279+
)
280+
}
281+
}

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/ProcessedCqueryResult.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ struct ProcessedCqueryResult {
2929
let bspURIsToBazelLabelsMap: [URI: String]
3030
let bspURIsToSrcsMap: [URI: SourcesItem]
3131
let srcToBspURIsMap: [URI: [URI]]
32-
let availableBazelLabels: Set<String>
3332
let topLevelLabelToRuleMap: [String: TopLevelRuleType]
3433
let bazelLabelToParentsMap: [String: [String]]
3534
}

Tests/SourceKitBazelBSPTests/BazelTargetQuerierParserImplTests.swift

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,24 +154,6 @@ struct BazelTargetQuerierParserImplTests {
154154
#expect(result.topLevelTargets[index] == expected)
155155
}
156156

157-
// Available Bazel labels
158-
#expect(
159-
result.availableBazelLabels
160-
== Set([
161-
"//HelloWorld:ExpandedTemplate",
162-
"//HelloWorld:GeneratedDummy",
163-
"//HelloWorld:HelloWorldLib",
164-
"//HelloWorld:HelloWorldTestsLib",
165-
"//HelloWorld:MacAppLib",
166-
"//HelloWorld:MacAppTestsLib",
167-
"//HelloWorld:MacCLIAppLib",
168-
"//HelloWorld:TodoModels",
169-
"//HelloWorld:TodoObjCSupport",
170-
"//HelloWorld:WatchAppLib",
171-
"//HelloWorld:WatchAppTestsLib",
172-
])
173-
)
174-
175157
// Top level label to rule map
176158
let expectedTopLevelLabelToRuleMap: [String: TopLevelRuleType] = [
177159
"//HelloWorld:HelloWorld": .iosApplication,

Tests/SourceKitBazelBSPTests/BazelTargetQuerierTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ struct BazelTargetQuerierTests {
3333
bspURIsToBazelLabelsMap: [:],
3434
bspURIsToSrcsMap: [:],
3535
srcToBspURIsMap: [:],
36-
availableBazelLabels: [],
3736
topLevelLabelToRuleMap: [:],
3837
bazelLabelToParentsMap: [:]
3938
)

0 commit comments

Comments
 (0)