refactor to use metadata, address code review comments

This commit is contained in:
Oliver Atkinson 2020-03-05 19:57:35 +00:00
parent 52fe8fd119
commit f0871503da
22 changed files with 94 additions and 47 deletions

View File

@ -80,7 +80,7 @@ public final class XCFrameworkBuilder: XCFrameworkBuilding {
let outputDirectory = try TemporaryDirectory(removeTreeOnDeinit: false)
let temporaryPath = try TemporaryDirectory(removeTreeOnDeinit: false)
logger.notice("Building .xcframework for \(target.name)".as(.section))
logger.notice("Building .xcframework for \(target.name)", metadata: .section)
// Build for the device
// Without the BUILD_LIBRARY_FOR_DISTRIBUTION argument xcodebuild doesn't generate the .swiftinterface file
@ -95,7 +95,7 @@ public final class XCFrameworkBuilder: XCFrameworkBuilding {
.buildSetting("SKIP_INSTALL", "NO"),
.buildSetting("BUILD_LIBRARY_FOR_DISTRIBUTION", "YES"))
.do(onSubscribed: {
logger.notice("Building \(target.name) for device".as(.subsection))
logger.notice("Building \(target.name) for device", metadata: .subsection)
})
// Build for the simulator
@ -113,7 +113,7 @@ public final class XCFrameworkBuilder: XCFrameworkBuilding {
.buildSetting("SKIP_INSTALL", "NO"),
.buildSetting("BUILD_LIBRARY_FOR_DISTRIBUTION", "YES"))
.do(onSubscribed: {
logger.notice("Building \(target.name) for simulator".as(.subsection))
logger.notice("Building \(target.name) for simulator", metadata: .subsection)
})
}
@ -125,7 +125,7 @@ public final class XCFrameworkBuilder: XCFrameworkBuilding {
let xcframeworkPath = outputDirectory.path.appending(component: "\(target.productName).xcframework")
let xcframeworkObservable = xcodeBuildController.createXCFramework(frameworks: frameworkpaths, output: xcframeworkPath)
.do(onSubscribed: {
logger.notice("Exporting xcframework for \(target.platform.caseValue)".as(.subsection))
logger.notice("Exporting xcframework for \(target.platform.caseValue)", metadata: .subsection)
})
return deviceArchiveObservable

View File

@ -88,7 +88,7 @@ final class WorkspaceGenerator: WorkspaceGenerating {
tuistConfig _: TuistConfig) throws -> AbsolutePath {
let workspaceName = "\(graph.name).xcworkspace"
logger.info("Generating workspace \(workspaceName)".as(.section))
logger.info("Generating workspace \(workspaceName)", metadata: .section)
/// Projects

View File

@ -81,7 +81,7 @@ final class CocoaPodsInteractor: CocoaPodsInteracting {
// The installation of Pods might fail if the local repository that contains the specs
// is outdated.
logger.info("Installing CocoaPods dependencies defined in \(node.podfilePath)".as(.section))
logger.info("Installing CocoaPods dependencies defined in \(node.podfilePath)", metadata: .section)
var mightNeedRepoUpdate: Bool = false
let outputClosure: ([UInt8]) -> Void = { bytes in

View File

@ -52,10 +52,10 @@ class EditCommand: NSObject, Command {
try! FileHandler.shared.delete(EditCommand.temporaryDirectory.path)
exit(0)
}
logger.info("Opening Xcode to edit the project. Press \("CTRL + C".green().bold()) once you are done editing")
logger.info("Opening Xcode to edit the project. Press \("CTRL + C", .keystroke) once you are done editing")
try opener.open(path: xcodeprojPath, wait: true)
} else {
logger.info("Xcode project generated at \(xcodeprojPath.pathString)".as(.success))
logger.info("Xcode project generated at \(xcodeprojPath.pathString)", metadata: .success)
}
}

View File

@ -63,7 +63,7 @@ class GenerateCommand: NSObject, Command {
let time = String(format: "%.3f", timer.stop())
logger.info("Project generated.".as(.success))
logger.info("Project generated.", metadata: .success)
logger.info("Total time taken: \(time)s")
}

View File

@ -50,6 +50,6 @@ class GraphCommand: NSObject, Command {
}
try FileHandler.shared.write(graph, path: path, atomically: true)
logger.info("Graph exported to \(path.pathString)".as(.success))
logger.info("Graph exported to \(path.pathString)", metadata: .success)
}
}

View File

@ -96,7 +96,7 @@ class InitCommand: NSObject, Command {
try generateTuistConfig(path: path)
try generateGitIgnore(path: path)
logger.info("Project generated at path \(path.pathString).".as(.success))
logger.info("Project generated at path \(path.pathString).", metadata: .success)
}

View File

@ -99,7 +99,7 @@ class LintCommand: NSObject, Command {
issues.append(contentsOf: graphLinter.lint(graph: graph))
if issues.isEmpty {
logger.notice("No linting issues found".as(.success))
logger.notice("No linting issues found", metadata: .success)
} else {
try issues.printAndThrowIfNeeded()
}

View File

@ -50,7 +50,7 @@ public class SetupLoader: SetupLoading {
.printAndThrowIfNeeded()
try setup.forEach { command in
if try !command.isMet(projectPath: path) {
logger.info("Configuring \(command.name)".as(.subsection))
logger.info("Configuring \(command.name, .command)", metadata: .subsection)
try command.meet(projectPath: path)
}
}

View File

@ -30,7 +30,13 @@ public struct UnhandledError: FatalError {
public let type: ErrorType = .bug
/// Error description.
public var description: String { "UnhandledError - \(error.localizedDescription)\n\(error)" }
public var description: String {
"""
We received an error that we couldn't handle:
- Localized description: \(error.localizedDescription)
- Error: \(error)"
"""
}
}
/// Fatal error protocol.

View File

@ -1,32 +1,39 @@
public enum ConsolePrettyToken: String {
case highlight
case success
case section
case subsection
case command
case keystroke
var tokens: Set<ConsoleToken> {
switch self {
case .highlight:
return [ .bold ]
case .success:
return [ .green, .bold ]
case .section:
return [ .lightCyan, .bold ]
case .subsection:
return [ .lightCyan ]
case .command:
return [ .white, .bold ]
case .keystroke:
return [ .cyan ]
}
}
}
extension String {
extension Logger.Metadata {
public func `as`(_ token: ConsolePrettyToken...) -> Logger.Message {
return Logger.Message("\(self, token)")
public static let colored: String = "is"
public static let successKey: String = "success"
public static var success: Logger.Metadata {
return [ colored: .string(successKey) ]
}
public static let sectionKey: String = "section"
public static var section: Logger.Metadata {
return [ colored: .string(sectionKey) ]
}
public static let subsectionKey: String = "subsection"
public static var subsection: Logger.Metadata {
return [ colored: .string(subsectionKey) ]
}
}

View File

@ -27,19 +27,15 @@ public struct DetailedLogHandler: LogHandler {
file: String, function: String, line: UInt
) {
var log: String = "\(timestamp()) \(level.rawValue, .highlight) \(label)"
var log: String = "\(timestamp()) \(level.rawValue) \(label)"
let mergedMetadata = metadata.map{ self.metadata.merging($0, uniquingKeysWith: { $1 }) } ?? self.metadata
let mergedMetadata = metadata.map { self.metadata.merging($0, uniquingKeysWith: { $1 }) } ?? self.metadata
if mergedMetadata.isEmpty == false {
log.append(mergedMetadata.pretty)
}
if Environment.shared.shouldOutputBeColoured {
log.append(message.colorize(for: level).description)
} else {
log.append(message.description)
}
log.append(message.description)
output(for: level).log(level: level, message: message, metadata: metadata, file: file, function: function, line: line)

View File

@ -1,30 +1,58 @@
@_exported import Logging
import class Foundation.ProcessInfo
let logger = Logger(label: "io.tuist.support")
import class Foundation.ProcessInfo
public struct LoggingConfig {
public enum LoggerType {
case console, detailed, osLog
}
public var loggerType: LoggerType
public var verbose: Bool
}
extension LoggingConfig {
public static var `default`: LoggingConfig {
let environment = ProcessInfo.processInfo.environment
let os_log = environment["TUIST_OS_LOG"] != nil
let detailed = environment["TUIST_DETAILED_LOG"] != nil
let verbose = environment["TUIST_VERBOSE"] != nil
if os_log {
return .init(loggerType: .osLog, verbose: verbose)
} else if detailed {
return .init(loggerType: .detailed, verbose: verbose)
} else {
return .init(loggerType: .console, verbose: verbose)
}
}
}
public enum LogOutput {
static var environment = ProcessInfo.processInfo.environment
public static func bootstrap() {
let os_log = environment["TUIST_OS_LOG"] != nil
let detailed = environment["TUIST_DETAILED_LOG"] != nil
public static func bootstrap(config: LoggingConfig = .default) {
let handler: VerboseLogHandler.Type
if os_log {
switch config.loggerType {
case .osLog:
handler = OSLogHandler.self
} else if detailed {
case .detailed:
handler = DetailedLogHandler.self
} else {
case .console:
handler = StandardLogHandler.self
}
let verbose = environment["TUIST_VERBOSE"] != nil
if verbose {
if config.verbose {
LoggingSystem.bootstrap(handler.verbose)
} else {
LoggingSystem.bootstrap(handler.init)

View File

@ -26,7 +26,18 @@ public struct StandardLogHandler: LogHandler {
let log: Logger.Message
if Environment.shared.shouldOutputBeColoured {
log = message.colorize(for: level)
switch metadata?[Logger.Metadata.colored] {
case .string(Logger.Metadata.successKey)?:
log = Logger.Message(stringLiteral: message.description.apply([ .green, .bold ]))
case .string(Logger.Metadata.sectionKey)?:
log = Logger.Message(stringLiteral: message.description.apply([ .cyan, .bold ]))
case .string(Logger.Metadata.subsectionKey)?:
log = Logger.Message(stringLiteral: message.description.apply([ .cyan ]))
default:
log = message.colorize(for: level)
}
} else {
log = message
}

View File

@ -1,11 +1,11 @@
import Foundation
import enum Basic.ProcessEnv
import enum TuistSupport.LogOutput
if CommandLine.arguments.contains("--verbose") {
try? ProcessEnv.setVar("TUIST_VERBOSE", value: "true")
}
import enum TuistSupport.LogOutput
LogOutput.bootstrap()
import TuistKit

View File

@ -1,6 +1,5 @@
import Foundation
import TuistEnvKit
import enum TuistSupport.LogOutput
LogOutput.bootstrap()