1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2022 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Foundation
import ArgumentParser
import SymbolKit
@main
struct DumpUnifiedGraph: ParsableCommand {
static let configuration = CommandConfiguration(
commandName: "dump-unified-graph",
abstract: "Collects a unified symbol graph from given inputs and renders it to JSON")
@Option(
help: ArgumentHelp(
"module's symbol graph to output",
discussion: "will infer a single module, but will fail if multiple modules are being loaded",
valueName: "name"))
var moduleName: String?
@Flag(inversion: .prefixedNo,
help: "whether to pretty-print the output JSON")
var prettyPrint: Bool = true
@Option(
name: .shortAndLong,
help: ArgumentHelp(
"output file to write to (default: standard out)",
valueName: "file"))
var output: String?
@Option(
help: ArgumentHelp(
"directory to recursively load symbol graphs from",
valueName: "dir"),
completion: .directory)
var symbolGraphDir: String?
@Argument(
help: ArgumentHelp(
"individual symbol graphs to load",
valueName: "file"),
completion: .file(extensions: ["json"]))
var files: [String] = []
mutating func validate() throws {
guard !files.isEmpty || symbolGraphDir != nil else {
throw ValidationError("Please provide files or a symbol graph directory")
}
if let symbolGraphDir = symbolGraphDir {
if !FileManager.default.fileExists(atPath: symbolGraphDir) {
throw ValidationError("Given symbol graph directory does not exist")
}
if !symbolGraphDir.hasSuffix("/") {
self.symbolGraphDir = symbolGraphDir.appending("/")
}
}
}
func run() throws {
var symbolGraphs = files
if let symbolGraphDir = symbolGraphDir {
symbolGraphs.append(contentsOf: loadSymbolGraphsFromDir(symbolGraphDir))
}
if symbolGraphs.isEmpty {
print("error: No symbol graphs were available")
throw ExitCode.failure
}
let decoder = JSONDecoder()
let collector = GraphCollector()
for symbolGraph in symbolGraphs {
let graphUrl = URL(fileURLWithPath: symbolGraph)
let decodedGraph = try decoder.decode(SymbolGraph.self, from: Data(contentsOf: graphUrl))
collector.mergeSymbolGraph(decodedGraph, at: graphUrl)
}
let (unifiedGraphs, _) = collector.finishLoading()
let outputGraph: UnifiedSymbolGraph
if let moduleName = moduleName {
if let graph = unifiedGraphs[moduleName] {
outputGraph = graph
} else {
print("error: The given module was not represented in the symbol graphs")
throw ExitCode.failure
}
} else {
if unifiedGraphs.count > 1 {
print("error: No module was given, but more than one module was represented in the symbol graphs")
throw ExitCode.failure
} else {
outputGraph = unifiedGraphs.values.first!
}
}
let encoder = JSONEncoder()
if #available(macOS 10.13, *) {
encoder.outputFormatting.insert(.sortedKeys)
}
if prettyPrint {
encoder.outputFormatting.insert(.prettyPrinted)
}
let encoded = try encoder.encode(outputGraph)
if let output = output, output != "-" {
FileManager.default.createFile(atPath: output, contents: encoded)
} else {
let outString = String(data: encoded, encoding: .utf8)
print(outString!)
}
}
}
func loadSymbolGraphsFromDir(_ dir: String) -> [String] {
let enumerator = FileManager.default.enumerator(atPath: dir)
var symbolGraphs: [String] = []
while let filename = enumerator?.nextObject() as? String {
if filename.hasSuffix(".symbols.json") {
symbolGraphs.append(dir.appending(filename))
}
}
return symbolGraphs
}
|