finish json reporter

This commit is contained in:
Roy Cao 2019-12-13 21:52:05 +08:00
parent e8b6e331e9
commit 0826b7ecba
8 changed files with 47 additions and 12 deletions

View File

@ -163,7 +163,9 @@ Rule inclusion:
Reporter inclusion: Reporter inclusion:
* xcode: Warnings displayed in the IDE. * xcode: Warnings displayed in the IDE.
* json: Generate a warnings json file. * json: Generate a json file named `pecker.result.json`, you can set path by `output_file`, if unspecified, the default is current project directory path.
![屏幕快照 2019-12-13 下午9.49.09.png](https://upload-images.jianshu.io/upload_images/2086987-29dbe4bb76af16ec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```yaml ```yaml
reporter: "xcode" reporter: "xcode"
@ -184,6 +186,8 @@ blacklist_files: # files to ignore during detecting, only need to add file name,
blacklist_symbols: # symbols to ignore during detecting, contains class, struct, enum, etc. blacklist_symbols: # symbols to ignore during detecting, contains class, struct, enum, etc.
- AppDelegate - AppDelegate
- viewDidLoad - viewDidLoad
output_file: "/Users/ming/Desktop/PeckerResultDirectory"
``` ```

View File

@ -157,7 +157,8 @@ extension UnusedExample {
报告方式包含: 报告方式包含:
* xcode: 在Xcode中显示warning。 * xcode: 在Xcode中显示warning。
* json: 生成warning的json文件。 * json: 生成名为`pecker.result.json`的文件,你可以通过`output_file`来自定义路径,如果没有指定,默认为当前检测项目的文件下的路径。
![屏幕快照 2019-12-13 下午9.49.09.png](https://upload-images.jianshu.io/upload_images/2086987-29dbe4bb76af16ec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```yaml ```yaml
reporter: "xcode" reporter: "xcode"
@ -178,6 +179,8 @@ blacklist_files: # files to ignore during detecting, only need to add file name,
blacklist_symbols: # symbols to ignore during detecting, contains class, struct, enum, etc. blacklist_symbols: # symbols to ignore during detecting, contains class, struct, enum, etc.
- AppDelegate - AppDelegate
- viewDidLoad - viewDidLoad
output_file: "/Users/ming/Desktop/PeckerResultDirectory"
``` ```

View File

@ -13,14 +13,14 @@ fileprivate func main(_ arguments: [String]) -> Int32 {
let configuration = try createConfiguration(options: options) let configuration = try createConfiguration(options: options)
let analyzer = try Analyzer(configuration: configuration) let analyzer = try Analyzer(configuration: configuration)
let unusedSources = try analyzer.analyze() let unusedSources = try analyzer.analyze()
configuration.reporter.report(sources: unusedSources) configuration.reporter.report(configuration, sources: unusedSources)
} catch { } catch {
log(error.localizedDescription, level: .error) log(error.localizedDescription, level: .error)
return 1 return 1
} }
return 0 return 0
case .version: case .version:
print("0.0.7") print("0.0.8")
return 0 return 0
} }
} }

View File

@ -18,6 +18,8 @@ public struct Configuration {
public let blacklistSymbols: [String] public let blacklistSymbols: [String]
public let outputFile: AbsolutePath
/// The project path /// The project path
public let projectPath: AbsolutePath public let projectPath: AbsolutePath
@ -35,7 +37,8 @@ public struct Configuration {
included: [AbsolutePath], included: [AbsolutePath],
excluded: [AbsolutePath], excluded: [AbsolutePath],
blacklistFiles: [String], blacklistFiles: [String],
blacklistSymbols: [String]) { blacklistSymbols: [String],
outputFile: AbsolutePath) {
self.projectPath = projectPath self.projectPath = projectPath
self.indexStorePath = indexStorePath self.indexStorePath = indexStorePath
self.indexDatabasePath = indexDatabasePath ?? NSTemporaryDirectory() + "index_\(getpid())" self.indexDatabasePath = indexDatabasePath ?? NSTemporaryDirectory() + "index_\(getpid())"
@ -45,6 +48,7 @@ public struct Configuration {
self.excluded = excluded self.excluded = excluded
self.blacklistFiles = blacklistFiles self.blacklistFiles = blacklistFiles
self.blacklistSymbols = blacklistSymbols self.blacklistSymbols = blacklistSymbols
self.outputFile = outputFile
} }
public init(projectPath: AbsolutePath, indexStorePath: String = "", indexDatabasePath: String? = nil) { public init(projectPath: AbsolutePath, indexStorePath: String = "", indexDatabasePath: String? = nil) {
@ -61,6 +65,7 @@ public struct Configuration {
let reporter = ReporterFactory.make(yamlConfiguration?.reporter) let reporter = ReporterFactory.make(yamlConfiguration?.reporter)
let rules = RuleFactory.make(yamlConfiguration?.disabledRules) let rules = RuleFactory.make(yamlConfiguration?.disabledRules)
let outputFilePath = AbsolutePath(yamlConfiguration?.outputFile ?? projectPath.asURL.path).appending(component: "pecker.result.json")
self.init(projectPath: projectPath, self.init(projectPath: projectPath,
indexStorePath: indexStorePath, indexStorePath: indexStorePath,
indexDatabasePath: indexDatabasePath, indexDatabasePath: indexDatabasePath,
@ -69,6 +74,7 @@ public struct Configuration {
included: (yamlConfiguration?.included ?? [""]).map{ projectPath.appending(component: $0)}, included: (yamlConfiguration?.included ?? [""]).map{ projectPath.appending(component: $0)},
excluded: (yamlConfiguration?.excluded ?? []).map{ projectPath.appending(component: $0)} , excluded: (yamlConfiguration?.excluded ?? []).map{ projectPath.appending(component: $0)} ,
blacklistFiles: yamlConfiguration?.blacklistFiles ?? [], blacklistFiles: yamlConfiguration?.blacklistFiles ?? [],
blacklistSymbols: yamlConfiguration?.blacklistSymbols ?? []) blacklistSymbols: yamlConfiguration?.blacklistSymbols ?? [],
outputFile: outputFilePath)
} }
} }

View File

@ -20,6 +20,9 @@ public struct YamlConfiguration: Decodable {
/// Acts as a blacklist, the symbols specified in this list will ignore /// Acts as a blacklist, the symbols specified in this list will ignore
public let blacklistSymbols: [String]? public let blacklistSymbols: [String]?
/// The path of the output json file
public let outputFile: String?
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case disabledRules = "disabled_rules" case disabledRules = "disabled_rules"
case reporter case reporter
@ -27,6 +30,7 @@ public struct YamlConfiguration: Decodable {
case excluded case excluded
case blacklistFiles = "blacklist_files" case blacklistFiles = "blacklist_files"
case blacklistSymbols = "blacklist_symbols" case blacklistSymbols = "blacklist_symbols"
case outputFile = "output_file"
} }
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
@ -37,6 +41,7 @@ public struct YamlConfiguration: Decodable {
self.excluded = try container.decodeIfPresent([String].self, forKey: .excluded) self.excluded = try container.decodeIfPresent([String].self, forKey: .excluded)
self.blacklistFiles = try container.decodeIfPresent([String].self, forKey: .blacklistFiles) self.blacklistFiles = try container.decodeIfPresent([String].self, forKey: .blacklistFiles)
self.blacklistSymbols = try container.decodeIfPresent([String].self, forKey: .blacklistSymbols) self.blacklistSymbols = try container.decodeIfPresent([String].self, forKey: .blacklistSymbols)
self.outputFile = try container.decodeIfPresent(String.self, forKey: .outputFile)
} }
} }
@ -49,6 +54,7 @@ extension YamlConfiguration: Hashable {
hasher.combine(excluded) hasher.combine(excluded)
hasher.combine(blacklistFiles) hasher.combine(blacklistFiles)
hasher.combine(blacklistSymbols) hasher.combine(blacklistSymbols)
hasher.combine(outputFile)
} }
public static func == (lhs: YamlConfiguration, rhs: YamlConfiguration) -> Bool { public static func == (lhs: YamlConfiguration, rhs: YamlConfiguration) -> Bool {
@ -57,6 +63,7 @@ extension YamlConfiguration: Hashable {
(lhs.included == rhs.included) && (lhs.included == rhs.included) &&
(lhs.excluded == rhs.excluded) && (lhs.excluded == rhs.excluded) &&
(lhs.blacklistFiles == rhs.blacklistFiles) && (lhs.blacklistFiles == rhs.blacklistFiles) &&
(lhs.blacklistSymbols == rhs.blacklistSymbols) (lhs.blacklistSymbols == rhs.blacklistSymbols) &&
(lhs.outputFile == rhs.outputFile)
} }
} }

View File

@ -2,8 +2,23 @@ import Foundation
public struct JSONReporter: Reporter { public struct JSONReporter: Reporter {
// TODO: - public func report(_ configuration: Configuration, sources: [SourceDetail]) {
public func report(sources: [SourceDetail]) { var entries = sources.map { $0.location.description }
let count = entries.count
entries.insert("count: \(count)", at: 0)
do {
try writeEntries(entries: entries, to: configuration.outputFile.asURL)
} catch {
log("Output json file failed: \(error.localizedDescription)", level: .warning)
}
}
}
private func writeEntries(entries: [String], to path: URL) throws {
do {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(entries)
try data.write(to: path, options: .atomic)
} }
} }

View File

@ -2,5 +2,5 @@ import Foundation
public protocol Reporter { public protocol Reporter {
func report(sources: [SourceDetail]) func report(_ configuration: Configuration, sources: [SourceDetail])
} }

View File

@ -3,7 +3,7 @@ import SwiftSyntax
public struct XcodeReporter: Reporter { public struct XcodeReporter: Reporter {
public func report(sources: [SourceDetail]) { public func report(_ configuration: Configuration, sources: [SourceDetail]) {
let diagnosticEngine = makeDiagnosticEngine() let diagnosticEngine = makeDiagnosticEngine()
for source in sources { for source in sources {
let message = Diagnostic.Message(.warning, "Pecker: \(source.sourceKind) \(source.name) was never used; consider removing it") let message = Diagnostic.Message(.warning, "Pecker: \(source.sourceKind) \(source.name) was never used; consider removing it")