Skip to content

Commit

Permalink
Bug fixes and more logs
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagohmcruz committed Nov 1, 2022
1 parent e95dd8d commit 1ec8fd2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 32 deletions.
77 changes: 45 additions & 32 deletions Examples/BazelBuildService/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,33 @@ private var configValues: [String: Any]? {
}
return dict
}
// Directory containing data used to fast load information when initializing BazelBuildService, e.g.,
// .json files containing source => output file mappings generated during Xcode project generation
private var xcbuildkitDataDir: String {
return "\(xcodeprojPath)/xcbuildkit.data"
}
// File containing config values that a consumer can set, see accepted keys below.
// Format is KEY=VALUE and one config per line
// TODO: Probably better to make this a separate struct with proper validation but will do that
// once the list of accepted keys is stable
private var xcbuildkitConfigPath: String {
return "\(xcodeprojPath)/xcbuildkit.config"
}
private var sourceOutputFileMapSuffix: String? {
return configValues?["BUILD_SERVICE_SOURE_OUTPUT_FILE_MAP_SUFFIX"] as? String
}
private var bazelWorkingDir: String? {
return configValues?["BUILD_SERVICE_BAZEL_EXEC_ROOT"] as? String
}
private var indexingEnabled: Bool {
return (configValues?["BUILD_SERVICE_INDEXING_ENABLED"] as? String ?? "") == "YES"
}
// Directory containing data used to fast load information when initializing BazelBuildService, e.g.,
// .json files containing source => output file mappings generated during Xcode project generation
private var xcbuildkitDataDir: String? {
return configValues?["BUILD_SERVICE_INDEXING_DATA_DIR"] as? String
}
private var progressBarEnabled: Bool {
return (configValues?["BUILD_SERVICE_PROGRESS_BAR_ENABLED"] as? String ?? "") == "YES"
}
private var configBEPPath: String? {
return configValues?["BUILD_SERVICE_BEP_PATH"] as? String
}
private var sourceOutputFileMapSuffix: String? {
return configValues?["BUILD_SERVICE_SOURCE_OUTPUT_FILE_MAP_SUFFIX"] as? String
}
private var bazelWorkingDir: String? {
return configValues?["BUILD_SERVICE_BAZEL_EXEC_ROOT"] as? String
}

/// This example listens to a BEP stream to display some output.
///
Expand Down Expand Up @@ -152,25 +152,27 @@ enum BasicMessageHandler {

return bplistData
}
// Check many conditions that need to be met in order to handle indexing and find the respect output file,
// Check many conditions that need to be met in order to handle indexing and returns the respect output file,
// the call site should abort and proxy the indexing request if this returns `nil`
static func outputFileForIndexingRequest(msg: XCBProtocolMessage) -> String? {
static func canHandleIndexingWithOutfile(msg: XCBProtocolMessage) -> String? {
// Nothing to do for non-indexing request types
guard let reqMsg = msg as? IndexingInfoRequested else {
return nil
}
// TODO: handle Swift
guard reqMsg.filePath.count > 0 && reqMsg.filePath != "<garbage>" && !reqMsg.filePath.hasSuffix(".swift") else {
// Nothing to do if indexing is disabled
guard indexingEnabled else {
return nil
}
// Indexing needs to be enabled via config file
guard indexingEnabled else {
// TODO: handle Swift
guard reqMsg.filePath.count > 0 && reqMsg.filePath != "<garbage>" && !reqMsg.filePath.hasSuffix(".swift") else {
log("[WARNING] Unsupported filePath for indexing: \(reqMsg.filePath)")
return nil
}
// In `BazelBuildService` the path to the working directory (i.e. execution_root) should always
// exists
guard bazelWorkingDir != nil else {
fatalError("[ERROR] Path to Bazel working directory not provided. Check `BUILD_SERVICE_BAZEL_EXEC_ROOT` in your config file.")
log("[WARNING] Could not find bazel working directory. Make sure `BUILD_SERVICE_BAZEL_EXEC_ROOT` is set in the config file.")
return nil
}

guard let outputFilePath = findOutputFileForSource(filePath: reqMsg.filePath, workingDir: reqMsg.workingDir) else {
Expand All @@ -182,6 +184,7 @@ enum BasicMessageHandler {
}
// Initialize in memory mappings from xcbuildkitDataDir if .json mappings files exist
static func initializeOutputFileMappingFromCache() {
guard let xcbuildkitDataDir = xcbuildkitDataDir else { return }
let fm = FileManager.default
do {
let jsons = try fm.contentsOfDirectory(atPath: xcbuildkitDataDir)
Expand All @@ -198,27 +201,30 @@ enum BasicMessageHandler {
static func loadSourceOutputFileMappingInfo(jsonFilename: String, jsonData: Data, updateCache: Bool = false) {
// Ensure workspace info is ready and .json can be decoded
guard let workspaceKey = workspaceKey else { return }
guard let xcbuildkitDataDir = xcbuildkitDataDir else { return }
guard let jsonValues = try? JSONSerialization.jsonObject(with: jsonData, options: [.allowFragments]) as? [String: String] else { return }

// Load .json contents into memory
initializeOutputFileForSourceIfNecessary(jsonFilename: jsonFilename)
outputFileForSource[workspaceKey]?[jsonFilename] = jsonValues
log("[INFO] Loaded mapping information into memory from: \(jsonFilename)")
log("[INFO] Loaded mapping information into memory for file: \(jsonFilename)")

// Update .json files cached under xcbuildkitDataDir for
// fast load next time we launch Xcode
do {
guard let jsonBasename = jsonFilename.components(separatedBy: "/").last else { return }
let jsonFilePath = "\(xcbuildkitDataDir)/\(jsonBasename)"
let json = URL(fileURLWithPath: jsonFilePath)
let fm = FileManager.default
if fm.fileExists(atPath: jsonFilePath) {
try fm.removeItem(atPath: jsonFilePath)
if updateCache {
do {
guard let jsonBasename = jsonFilename.components(separatedBy: "/").last else { return }
let jsonFilePath = "\(xcbuildkitDataDir)/\(jsonBasename)"
let json = URL(fileURLWithPath: jsonFilePath)
let fm = FileManager.default
if fm.fileExists(atPath: jsonFilePath) {
try fm.removeItem(atPath: jsonFilePath)
}
try jsonData.write(to: json)
log("[INFO] Updated cache for file \(jsonFilePath)")
} catch {
log("[ERROR] Failed to update cache under \(xcbuildkitDataDir) for file \(jsonFilename) with err: \(error.localizedDescription)")
}
try jsonData.write(to: json)
log("[INFO] Updated cache in: \(jsonFilePath)")
} catch {
log("[ERROR] Failed to update cache under \(xcbuildkitDataDir) for file \(jsonFilename) with err: \(error.localizedDescription)")
}
}
// This loop looks for JSON files with a known suffix `BUILD_SERVICE_SOURE_OUTPUT_FILE_MAP_SUFFIX` and loads the mapping
Expand Down Expand Up @@ -248,6 +254,7 @@ enum BasicMessageHandler {
guard let workspaceKey = workspaceKey, jsonFilename.hasSuffix(sourceOutputFileMapSuffix) else { continue }

// Load .json contents into memory
log("[INFO] Parsed \(jsonFilename) from BEP.")
loadSourceOutputFileMappingInfo(jsonFilename: jsonFilename, jsonData: jsonData, updateCache: true)
}
}
Expand Down Expand Up @@ -313,7 +320,7 @@ enum BasicMessageHandler {
if let responseData = try? message.encode(encoder) {
bkservice.write(responseData)
}
} else if let outputFilePath = outputFileForIndexingRequest(msg: msg) {
} else if let outputFilePath = canHandleIndexingWithOutfile(msg: msg) {
// Settings values needed to compose the payload below
let reqMsg = msg as! IndexingInfoRequested
workingDir = bazelWorkingDir ?? reqMsg.workingDir
Expand Down Expand Up @@ -345,7 +352,13 @@ enum BasicMessageHandler {
}
}
}
log("[INFO] Proxying request")
// Useful during development/debugging and to troubleshoot issues on machines running xcbuildkit
if let identifier = input.identifier {
log("[INFO] Proxying request with type: \(identifier)")
if identifier == "INDEXING_INFO_REQUESTED" {
log("[WARNING] BazelBuildService failed to handle indexing request, message will be proxied instead.")
}
}
xcbbuildService.write(data)
}
}
Expand Down
13 changes: 13 additions & 0 deletions Sources/XCBProtocol/Packer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ public struct XCBInputStream {
public let data: Data
public var stream: IndexingIterator<[MessagePackValue]>
public let first: MessagePackValue
// Used for debugging only, assumes the first .string found is the identifier for this msg
public var identifier: String? {
var mutableSelf = self
while let value = mutableSelf.next() {
switch value {
case let XCBRawValue.string(str):
return str
default:
continue
}
}
return nil
}

// This thing reads in a result - maybe it will not do this.
public init (result: [MessagePackValue], data: Data) {
Expand Down

0 comments on commit 1ec8fd2

Please sign in to comment.