in src/TulsiGenerator/BazelAspectInfoExtractor.swift [277:437]
func parseTulsiTargetFileImpl(_ filename: String) throws -> RuleEntry {
guard let data = fileManager.contents(atPath: filename) else {
throw ExtractorError.parsingFailed("The file could not be read")
}
guard let dict = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? [String: AnyObject] else {
throw ExtractorError.parsingFailed("Contents are not a dictionary")
}
func getRequiredField(_ field: String) throws -> String {
guard let value = dict[field] as? String else {
throw ExtractorError.parsingFailed("Missing required '\(field)' field")
}
return value
}
let ruleLabel = try getRequiredField("label")
let ruleType = try getRequiredField("type")
let attributes = dict["attr"] as? [String: AnyObject] ?? [:]
func MakeBazelFileInfos(_ attributeName: String) -> [BazelFileInfo] {
let infos = dict[attributeName] as? [[String: AnyObject]] ?? []
var bazelFileInfos = [BazelFileInfo]()
for info in infos {
if let pathInfo = BazelFileInfo(info: info as AnyObject?) {
bazelFileInfos.append(pathInfo)
}
}
return bazelFileInfos
}
let artifacts = MakeBazelFileInfos("artifacts")
var sources = MakeBazelFileInfos("srcs")
// Appends BazelFileInfo objects to the given array for any info dictionaries representing
// source code or (potential) source code containers. The directoryArtifacts set is also
// populated as a side effect.
var directoryArtifacts = Set<String>()
func appendGeneratedSourceArtifacts(_ infos: [[String: AnyObject]],
to artifacts: inout [BazelFileInfo]) {
for info in infos {
guard let pathInfo = BazelFileInfo(info: info as AnyObject?) else {
continue
}
if pathInfo.isDirectory {
directoryArtifacts.insert(pathInfo.fullPath)
} else {
guard let fileUTI = pathInfo.uti, fileUTI.hasPrefix("sourcecode.") else {
continue
}
}
artifacts.append(pathInfo)
}
}
let generatedSourceInfos = dict["generated_files"] as? [[String: AnyObject]] ?? []
appendGeneratedSourceArtifacts(generatedSourceInfos, to: &sources)
var nonARCSources = MakeBazelFileInfos("non_arc_srcs")
let generatedNonARCSourceInfos = dict["generated_non_arc_files"] as? [[String: AnyObject]] ?? []
appendGeneratedSourceArtifacts(generatedNonARCSourceInfos, to: &nonARCSources)
let includePaths: [RuleEntry.IncludePath]?
if let includes = dict["includes"] as? [String] {
includePaths = includes.map() {
RuleEntry.IncludePath($0, directoryArtifacts.contains($0))
}
} else {
includePaths = nil
}
let objcDefines = dict["objc_defines"] as? [String]
let swiftDefines = dict["swift_defines"] as? [String]
let deps = dict["deps"] as? [String] ?? []
let dependencyLabels = Set(deps.map({ BuildLabel($0) }))
let testDeps = dict["test_deps"] as? [String] ?? []
let testDependencyLabels = Set(testDeps.map { BuildLabel($0) })
let frameworkImports = MakeBazelFileInfos("framework_imports")
let buildFilePath = dict["build_file"] as? String
let osDeploymentTarget = dict["os_deployment_target"] as? String
let secondaryArtifacts = MakeBazelFileInfos("secondary_product_artifacts")
let swiftLanguageVersion = dict["swift_language_version"] as? String
let swiftToolchain = dict["swift_toolchain"] as? String
let swiftTransitiveModules = MakeBazelFileInfos("swift_transitive_modules")
let objCModuleMaps = MakeBazelFileInfos("objc_module_maps")
let moduleName = dict["module_name"] as? String
let extensions: Set<BuildLabel>?
if let extensionList = dict["extensions"] as? [String] {
extensions = Set(extensionList.map({ BuildLabel($0) }))
} else {
extensions = nil
}
let appClips: Set<BuildLabel>?
if let appClipsList = dict["app_clips"] as? [String] {
appClips = Set(appClipsList.map({ BuildLabel($0) }))
} else {
appClips = nil
}
let bundleID = dict["bundle_id"] as? String
let bundleName = dict["bundle_name"] as? String
let productType = dict["product_type"] as? String
let platformType = dict["platform_type"] as? String
let xcodeVersion = dict["xcode_version"] as? String
let targetProductType: PBXTarget.ProductType?
if let productTypeStr = productType {
// Better be a type that we support, otherwise it's an error on our end.
if let actualProductType = PBXTarget.ProductType(rawValue: productTypeStr) {
targetProductType = actualProductType
} else {
throw ExtractorError.parsingFailed("Unsupported product type: \(productTypeStr)")
}
} else {
targetProductType = nil
}
var extensionType: String?
if targetProductType?.isiOSAppExtension ?? false, let infoplistPath = dict["infoplist"] as? String {
let plistPath = executionRootURL.appendingPathComponent(infoplistPath).path
guard let info = NSDictionary(contentsOfFile: plistPath) else {
throw ExtractorError.parsingFailed("Unable to load extension plist file: \(plistPath)")
}
guard let _extensionType = info.value(forKeyPath: "NSExtension.NSExtensionPointIdentifier") as? String else {
throw ExtractorError.parsingFailed("Missing NSExtensionPointIdentifier in extension plist: \(plistPath)")
}
extensionType = _extensionType
}
let ruleEntry = RuleEntry(label: ruleLabel,
type: ruleType,
attributes: attributes,
artifacts: artifacts,
sourceFiles: sources,
nonARCSourceFiles: nonARCSources,
dependencies: dependencyLabels,
testDependencies: testDependencyLabels,
frameworkImports: frameworkImports,
secondaryArtifacts: secondaryArtifacts,
extensions: extensions,
appClips: appClips,
bundleID: bundleID,
bundleName: bundleName,
productType: targetProductType,
platformType: platformType,
osDeploymentTarget: osDeploymentTarget,
buildFilePath: buildFilePath,
objcDefines: objcDefines,
swiftDefines: swiftDefines,
includePaths: includePaths,
swiftLanguageVersion: swiftLanguageVersion,
swiftToolchain: swiftToolchain,
swiftTransitiveModules: swiftTransitiveModules,
objCModuleMaps: objCModuleMaps,
moduleName: moduleName,
extensionType: extensionType,
xcodeVersion: xcodeVersion)
progressNotifier?.incrementValue()
return ruleEntry
}