CommandLineToolkit
91 строка · 2.8 Кб
1import FileSystem
2import Foundation
3import PathLib
4import ProcessController
5
6public final class ClocTool: Cloc {
7private let filePropertiesProvider: FilePropertiesProvider
8private let processControllerProvider: ProcessControllerProvider
9
10private struct ClocOutput: Codable, CustomStringConvertible {
11struct SUM: Codable {
12let code: Int
13}
14
15let SUM: SUM
16
17var description: String {
18"sum.code=\(self.SUM.code)"
19}
20}
21
22public init(
23filePropertiesProvider: FilePropertiesProvider,
24processControllerProvider: ProcessControllerProvider
25) {
26self.filePropertiesProvider = filePropertiesProvider
27self.processControllerProvider = processControllerProvider
28}
29
30private let clocBinaryPaths = [
31AbsolutePath("/usr/local/bin/cloc"),
32AbsolutePath("/opt/homebrew/bin/cloc"),
33]
34
35public func countLinesOfCode(
36sourceFiles: [AbsolutePath],
37includeLangOptions: Set<IncludeLangOption>
38) throws -> Int {
39for clocBinaryPath in clocBinaryPaths {
40if !filePropertiesProvider.exists(path: clocBinaryPath) {
41continue
42}
43
44if try filePropertiesProvider.properties(path: clocBinaryPath).isExecutable {
45return try run(
46clocBinaryPath: clocBinaryPath,
47sourceFiles: sourceFiles,
48includeLangOptions: includeLangOptions
49)
50}
51}
52
53throw "Could not locate cloc binary"
54}
55
56private func run(
57clocBinaryPath: AbsolutePath,
58sourceFiles: [AbsolutePath],
59includeLangOptions: Set<IncludeLangOption>
60) throws -> Int {
61do {
62let processController = try processControllerProvider.createProcessController(
63subprocess: Subprocess(
64arguments: [
65clocBinaryPath,
66"--json",
67"--include-lang=\(includeLangOptions.map(\.rawValue).joined(separator: ","))"
68] + sourceFiles
69)
70)
71var clocOutput = Data()
72processController.onStdout { _, data, _ in clocOutput.append(contentsOf: data) }
73
74try processController.startAndWaitForSuccessfulTermination()
75
76if let parsedOutput = try? JSONDecoder().decode(ClocOutput.self, from: clocOutput) {
77return parsedOutput.SUM.code
78} else {
79return 0
80}
81} catch {
82throw """
83Failed to get cloc
84from \(sourceFiles)
85using \(clocBinaryPath)
86for \(includeLangOptions)
87becasue of \(error)
88"""
89}
90}
91}
92