diff --git a/Package.swift b/Package.swift index cb777696a0..7e1d4e050a 100644 --- a/Package.swift +++ b/Package.swift @@ -94,7 +94,7 @@ let package = Package( .target( name: "SwiftLintCore", dependencies: [ - .product(name: "CryptoSwift", package: "CryptoSwift", condition: .when(platforms: [.linux])), + .product(name: "CryptoSwift", package: "CryptoSwift", condition: .when(platforms: [.linux, .windows])), .target(name: "DyldWarningWorkaround", condition: .when(platforms: [.macOS])), .product(name: "SourceKittenFramework", package: "SourceKitten"), .product(name: "SwiftIDEUtils", package: "swift-syntax"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift index 0fdef2d9ef..91765f8e9c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift @@ -233,7 +233,7 @@ private extension String { var strippingURLs: String { let range = fullNSRange // Workaround for Linux until NSDataDetector is available - #if os(Linux) + #if os(Linux) || os(Windows) // Regex pattern from http://daringfireball.net/2010/07/improved_regex_for_matching_urls let pattern = "(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)" + "(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*" + diff --git a/Source/SwiftLintFramework/Configuration+CommandLine.swift b/Source/SwiftLintFramework/Configuration+CommandLine.swift index 2935f2fc79..b875a0e888 100644 --- a/Source/SwiftLintFramework/Configuration+CommandLine.swift +++ b/Source/SwiftLintFramework/Configuration+CommandLine.swift @@ -69,7 +69,7 @@ private func fileCount(from envVar: String) throws(SwiftLintError) -> Int { return count } -#if os(Linux) +#if os(Linux) || os(Windows) private func autoreleasepool(block: () -> T) -> T { block() } #endif diff --git a/Source/SwiftLintFramework/Configuration/Configuration+Remote.swift b/Source/SwiftLintFramework/Configuration/Configuration+Remote.swift index c083290c8a..761e8de314 100644 --- a/Source/SwiftLintFramework/Configuration/Configuration+Remote.swift +++ b/Source/SwiftLintFramework/Configuration/Configuration+Remote.swift @@ -5,6 +5,10 @@ import SourceKittenFramework import FoundationNetworking #endif +#if os(Windows) +import func WinSDK.Sleep +#endif + internal extension Configuration.FileGraph.FilePath { // MARK: - Properties: Remote Cache /// This should never be touched. @@ -83,7 +87,11 @@ internal extension Configuration.FileGraph.FilePath { while true { if taskDone { break } if Date().timeIntervalSince(startDate) > timeout { task.cancel(); break } +#if os(Windows) + Sleep(50) +#else usleep(50_000) // Sleep for 50 ms +#endif } // Handle wrong data diff --git a/Source/SwiftLintFramework/Helpers/Glob.swift b/Source/SwiftLintFramework/Helpers/Glob.swift index 953819fd15..0d67228d3f 100644 --- a/Source/SwiftLintFramework/Helpers/Glob.swift +++ b/Source/SwiftLintFramework/Helpers/Glob.swift @@ -9,6 +9,10 @@ import func Musl.glob #endif #endif +#if os(Windows) +import WinSDK +#endif + // Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3 struct Glob { @@ -20,6 +24,28 @@ struct Glob { return expandGlobstar(pattern: pattern) .reduce(into: [String]()) { paths, pattern in +#if os(Windows) + URL(fileURLWithPath: pattern).withUnsafeFileSystemRepresentation { + var ffd = WIN32_FIND_DATAW() + + let hDirectory: HANDLE = String(cString: $0!).withCString(encodedAs: UTF16.self) { + FindFirstFileW($0, &ffd) + } + if hDirectory == INVALID_HANDLE_VALUE { return } + defer { FindClose(hDirectory) } + + repeat { + let path: String = withUnsafePointer(to: &ffd.cFileName) { + $0.withMemoryRebound(to: UInt16.self, + capacity: MemoryLayout.size(ofValue: $0) / MemoryLayout.size) { + String(decodingCString: $0, as: UTF16.self) + } + } + if path == "." || path == ".." { continue } + paths.append(path) + } while FindNextFileW(hDirectory, &ffd) + } +#else var globResult = glob_t() defer { globfree(&globResult) } @@ -31,6 +57,7 @@ struct Glob { if glob(pattern, flags, nil, &globResult) == 0 { paths.append(contentsOf: populateFiles(globResult: globResult)) } +#endif } .unique .sorted() @@ -92,6 +119,7 @@ struct Glob { return isDirectory && isDirectoryBool.boolValue } +#if !os(Windows) private static func populateFiles(globResult: glob_t) -> [String] { #if os(Linux) let matchCount = globResult.gl_pathc @@ -102,4 +130,5 @@ struct Glob { globResult.gl_pathv[index].flatMap { String(validatingUTF8: $0) } } } +#endif } diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 4af32083a4..4c458942dc 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -444,7 +444,7 @@ private actor CorrectionsBuilder { } private func memoryUsage() -> String? { -#if os(Linux) +#if os(Linux) || os(Windows) return nil #else var info = mach_task_basic_info() diff --git a/Source/SwiftLintFramework/ProgressBar.swift b/Source/SwiftLintFramework/ProgressBar.swift index b5a08ab62f..32253a9da5 100644 --- a/Source/SwiftLintFramework/ProgressBar.swift +++ b/Source/SwiftLintFramework/ProgressBar.swift @@ -52,7 +52,7 @@ actor ProgressBar { } } -#if os(Linux) +#if os(Linux) || os(Windows) // swiftlint:disable:next identifier_name private let NSEC_PER_SEC = 1_000_000_000 #endif diff --git a/Source/swiftlint/Commands/Rules.swift b/Source/swiftlint/Commands/Rules.swift index 816551a0e5..6c812c411b 100644 --- a/Source/swiftlint/Commands/Rules.swift +++ b/Source/swiftlint/Commands/Rules.swift @@ -2,6 +2,9 @@ import ArgumentParser import Foundation import SwiftLintFramework import SwiftyTextTable +#if os(Windows) +import WinSDK +#endif private typealias SortedRules = [(String, any Rule.Type)] @@ -141,6 +144,13 @@ private extension TextTable { private struct Terminal { static func currentWidth() -> Int { +#if os(Windows) + var csbi = CONSOLE_SCREEN_BUFFER_INFO() + guard GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) else { + return 80 + } + return Int(csbi.srWindow.Right - csbi.srWindow.Left) + 1 +#else var size = winsize() #if os(Linux) _ = ioctl(CInt(STDOUT_FILENO), UInt(TIOCGWINSZ), &size) @@ -148,5 +158,6 @@ private struct Terminal { _ = ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) #endif return Int(size.ws_col) +#endif } }