Skip to content
Permalink
Browse files

Add TokamakLogger (#104)

* Init TokamakLogger

* Add TokamakLogger

* Apply swiftformat

* Fix var name

* Add TokamakLogger to project

* Add TokamakLoggerTest

* Remove unused code form TokamakLogger

* Remove logLevel proxying

* Add TokamakLoggerTest

* Add TokamakLoggerTest

* Add TokamakLogger to TokamakCLI

* Remove logLevel assignment

* Add TokamakCLI options bloc to Linter.md

* Remove force unwrap

* Add Logger

* Refactor TokamakLogHandler

* Apply swift format

* Fix error names

* Make error enum public
  • Loading branch information...
hodovani committed Jun 4, 2019
1 parent 8cdb198 commit d0016c3141f0af6ae1a2a24bc021723a9259fb14
@@ -1,6 +1,15 @@
{
"object": {
"pins": [
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
"revision": "f4240bf022a69815241a883c03645444b58ac553",
"version": "1.1.0"
}
},
{
"package": "SwiftSyntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
@@ -40,6 +40,7 @@ let package = Package(
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/apple/swift-syntax.git", .exact("0.50000.0")),
.package(url: "https://github.com/jakeheis/SwiftCLI", from: "5.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.1.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define
@@ -72,7 +73,7 @@ let package = Package(
),
.target(
name: "TokamakLint",
dependencies: ["SwiftSyntax"]
dependencies: ["SwiftSyntax", "Logging"]
),
.testTarget(
name: "TokamakTests",
@@ -6,34 +6,48 @@
//
import Foundation
import Logging
import SwiftCLI
import TokamakLint

class LintCommand: Command {
let name = "lint"
let shortDescription = "Lint folder or file"
let path = Parameter()
let logFilePath = Key<String>("-l", "--log-file", description: "The log file location")

func execute() throws {
if path.value.contains(".swift") {
// setup logger
LoggingSystem.bootstrap {
var tokamakLogHandler = TokamakLogHandler(label: $0)
do {
try lintFile("\(path.value)")
try tokamakLogHandler.setup(path: self.logFilePath.value)
} catch {
print("Can't lint file")
print(error)
}
return tokamakLogHandler
}
let logger = Logger(label: "TokamakCLI Output")

if path.value.contains(".swift") {
do {
try lintFile("\(path.value)", logger: logger)
} catch {
logger.info("Can't lint file")
logger.info("\(error)")
}
} else {
do {
try lintFolder("\(path.value)")
try lintFolder("\(path.value)", logger: logger)
} catch {
print("Can't lint folder")
print(error)
logger.info("Can't lint folder")
logger.info("\(error)")
}
}
}
}

let TokamakCLI = CLI(name: "TokamakCLI", version: "0.1.2", description: "Tokamak CLI tools")
let tokamakCLI = CLI(name: "TokamakCLI", version: "0.1.2", description: "Tokamak CLI tools")

TokamakCLI.commands = [LintCommand()]
TokamakCLI.goAndExit()
tokamakCLI.commands = [LintCommand()]
tokamakCLI.goAndExit()
@@ -6,9 +6,10 @@
//
import Foundation
import Logging
import SwiftSyntax

public func lintFolder(_ path: String) throws {
public func lintFolder(_ path: String, logger: Logger) throws {
let resourceKeys: [URLResourceKey] = [.creationDateKey, .isDirectoryKey]
let baseurl = URL(fileURLWithPath: path)
guard let enumerator = FileManager
@@ -25,22 +26,22 @@ public func lintFolder(_ path: String) throws {
}
let count = enumerator.count
let enumerated = enumerator.enumerated()

for (i, fileURL) in enumerated {
print("Linting ",
"\(fileURL.lastPathComponent) ",
"(\(i + 1)/\(count))")
logger.info("Linting \(fileURL.lastPathComponent) (\(i + 1)/\(count))")
let errors = try checkFile(fileURL.path)
if errors.count > 0 {
print(XcodeReporter.generateReport(errors))
logger.info("\(XcodeReporter.generateReport(errors))")
}
}
}

public func lintFile(_ path: String) throws {
print("Linting \(path)")
public func lintFile(_ path: String, logger: Logger) throws {
logger.info("Linting \(path)\n")

let errors = try checkFile(path)
if errors.count > 0 {
print(XcodeReporter.generateReport(errors))
logger.info("\(XcodeReporter.generateReport(errors))")
}
}

@@ -0,0 +1,101 @@
//
// TokamakLogHandler.swift
// TokamakLint
//
// Created by Matvii Hodovaniuk on 5/30/19.
//
import Foundation
import Logging

public enum TokamakLintError: Error {
case logFileCreationFailed
case logMessageEncodingFailed
}

public struct Outputs: OptionSet {
public init(rawValue: Int) {
self.rawValue = rawValue
}

public let rawValue: Int

public static let stdout = Outputs(rawValue: 1)
public static let file = Outputs(rawValue: 2)
}

public struct TokamakLogHandler: LogHandler {
public var metadata: Logger.Metadata = [:]
public var outputs = [Outputs.stdout]
private var fileManager: FileManager?
private var fileHandle: FileHandle?
public var logLevel: Logger.Level = .info

public init(label: String) {}

public mutating func setup(path: String?) throws {
fileManager = FileManager.default
if let path = path {
if fileManager?.fileExists(atPath: path) == false {
fileManager?.createFile(atPath: path, contents: "".data(using: .utf8))
}
guard let fileHandle = try? FileHandle(
forWritingTo: URL(fileURLWithPath: path)
) else {
throw TokamakLintError.logFileCreationFailed
}

self.fileHandle = fileHandle
outputs = [.stdout, .file]
}
}

public func log(
level: Logger.Level,
message: Logger.Message,
metadata: Logger.Metadata?,
file: String,
function: String,
line: UInt
) {
if outputs.contains(Outputs.stdout) {
print(message.description)
}

if outputs.contains(Outputs.file) {
do {
try write(message.description)
} catch {
print(error)
}
}
}

public func log(message: Logger.Message) {
log(
level: logLevel,
message: message,
metadata: .none,
file: "",
function: "",
line: 0
)
}

private func write(_ string: String) throws {
fileHandle?.seekToEndOfFile()
guard let data = "\(string)\n".data(using: .utf8) else {
throw TokamakLintError.logMessageEncodingFailed
}
fileHandle?.write(data)
}

public subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
get {
return metadata[metadataKey]
}
set(newValue) {
metadata[metadataKey] = newValue
}
}
}
@@ -23,7 +23,7 @@ struct XcodeReporter: Reporter {
"\(violation.location): warning: ",
"\(violation.ruleDescription.name) Violation: ",
violation.reason,
" (\(violation.ruleDescription.identifier))",
" (\(violation.ruleDescription.identifier))\n",
].joined()
}
}
@@ -0,0 +1,64 @@
//
// LoggerTest.swift
// TokamakCLITests
//
// Created by Matvii Hodovaniuk on 5/31/19.
//
import Logging
@testable import TokamakLint
import XCTest

final class TokamakLogHandlerTests: XCTestCase {
func testLogToFile() throws {
let fm = FileManager.default
// create url to test file
guard let url = fm.urls(
for: FileManager.SearchPathDirectory.documentDirectory,
in: FileManager.SearchPathDomainMask.userDomainMask
)
.last?.appendingPathComponent("test_log.txt")
else { return }

// clear file
let text = ""
try text.write(toFile: url.path, atomically: false, encoding: .utf8)

let firstMessage: Logger.Message = "Information message"
let secondMessage: Logger.Message = "Warning message"
let allMessages = "\(firstMessage)\(secondMessage)"

LoggingSystem.bootstrap {
var tokamakLogHandler = TokamakLogHandler(label: $0)
do {
try tokamakLogHandler.setup(path: url.path)
} catch {
print(error)
}

tokamakLogHandler.outputs = [.stdout, .file]
return tokamakLogHandler
}
let logger = Logger(label: "TokamakCLI Output")

logger.info(firstMessage)

XCTAssertEqual(
String(
try String(contentsOf: url, encoding: .utf8)
.filter { !"\n".contains($0) }
),
String(firstMessage.description)
)

logger.info(secondMessage)

XCTAssertEqual(
String(
try String(contentsOf: url, encoding: .utf8)
.filter { !"\n".contains($0) }
),
String(allMessages.description)
)
}
}
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

0 comments on commit d0016c3

Please sign in to comment.
You can’t perform that action at this time.