SwiftLint/Source/swiftlint/Helpers/ProgressBar.swift

64 lines
2.0 KiB
Swift

import Dispatch
import Foundation
import SwiftLintFramework
// Inspired by https://github.com/jkandzi/Progress.swift
actor ProgressBar {
private var index = 1
private var lastPrintedTime: TimeInterval = 0.0
private let startTime = uptime()
private let count: Int
init(count: Int) {
self.count = count
}
func initialize() {
// When progress is printed, the previous line is reset, so print an empty line before anything else
queuedPrintError("")
}
func printNext() {
guard index <= count else { return }
let currentTime = uptime()
if currentTime - lastPrintedTime > 0.1 || index == count {
let lineReset = "\u{1B}[1A\u{1B}[K"
let bar = makeBar()
let timeEstimate = makeTimeEstimate(currentTime: currentTime)
let lineContents = "\(index) of \(count) \(bar) \(timeEstimate)"
queuedPrintError("\(lineReset)\(lineContents)")
lastPrintedTime = currentTime
}
index += 1
}
// MARK: - Private
private func makeBar() -> String {
let barLength = 30
let completedBarElements = Int(Double(barLength) * (Double(index) / Double(count)))
let barArray = Array(repeating: "=", count: completedBarElements) +
Array(repeating: " ", count: barLength - completedBarElements)
return "[\(barArray.joined())]"
}
private func makeTimeEstimate(currentTime: TimeInterval) -> String {
let totalTime = currentTime - startTime
let itemsPerSecond = Double(index) / totalTime
let estimatedTimeRemaining = Double(count - index) / itemsPerSecond
let estimatedTimeRemainingString = "\(Int(estimatedTimeRemaining))s"
return "ETA: \(estimatedTimeRemainingString) (\(Int(itemsPerSecond)) files/s)"
}
}
#if os(Linux)
// swiftlint:disable:next identifier_name
private let NSEC_PER_SEC = 1_000_000_000
#endif
private func uptime() -> TimeInterval {
Double(DispatchTime.now().uptimeNanoseconds) / Double(NSEC_PER_SEC)
}