From e44c1efb81fc49e2736a18766ef7f92a1c632383 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 5 Oct 2022 00:54:24 +0000 Subject: [PATCH 1/3] swift package resolve --- Package.resolved | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Package.resolved b/Package.resolved index 554f426..3b1be3c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -28,6 +28,15 @@ "version": "1.0.3" } }, + { + "package": "swift-crypto", + "repositoryURL": "https://github.com/apple/swift-crypto.git", + "state": { + "branch": null, + "revision": "ddb07e896a2a8af79512543b1c7eb9797f8898a5", + "version": "1.1.7" + } + }, { "package": "SWXMLHash", "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", From 6b5aad3907c778a4b98fbeeaaa6098d913a3fb29 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 5 Oct 2022 00:54:51 +0000 Subject: [PATCH 2/3] Add `--cache-path` option In SwiftPM Plugin, a process cannot write file even at tmp dir. This option allows users to specify an writable path. --- .../Commands/ValidateCommand.swift | 5 ++ Sources/IBLinterKit/Config/Config.swift | 6 +- Sources/IBLinterKit/Utils/LintCache.swift | 35 ++++++++---- .../Utils/LintCacheTests.swift | 57 +++++++++++++++---- 4 files changed, 80 insertions(+), 23 deletions(-) diff --git a/Sources/IBLinterFrontend/Commands/ValidateCommand.swift b/Sources/IBLinterFrontend/Commands/ValidateCommand.swift index b3b2d2f..388e851 100644 --- a/Sources/IBLinterFrontend/Commands/ValidateCommand.swift +++ b/Sources/IBLinterFrontend/Commands/ValidateCommand.swift @@ -19,6 +19,8 @@ struct ValidateCommand: ParsableCommand { var reporter: String? @Option(name: .long, help: "the path to IBLint's configuration file", completion: .file()) var configurationFile: String? + @Option(name: .long, help: "the directory of the cache used when linting", completion: .directory) + var cachePath: String? @Argument(help: "included files/paths to lint. This is ignored if you specified included paths in your yml configuration file.", completion: .file()) var included: [String] = [] @@ -38,6 +40,9 @@ struct ValidateCommand: ParsableCommand { if config.included.isEmpty { config.included = included } + if let cachePath = cachePath { + config.cachePath = cachePath + } let validator = Validator() let violations = validator.validate(workDirectory: workDirectory, config: config) diff --git a/Sources/IBLinterKit/Config/Config.swift b/Sources/IBLinterKit/Config/Config.swift index 8a040e1..5d45421 100644 --- a/Sources/IBLinterKit/Config/Config.swift +++ b/Sources/IBLinterKit/Config/Config.swift @@ -21,6 +21,7 @@ public struct Config: Codable { public let reporter: String public let disableWhileBuildingForIB: Bool public let ignoreCache: Bool + public var cachePath: String? enum CodingKeys: String, CodingKey { case disabledRules = "disabled_rules" @@ -35,6 +36,7 @@ public struct Config: Codable { case reporter = "reporter" case disableWhileBuildingForIB = "disable_while_building_for_ib" case ignoreCache = "ignore_cache" + case cachePath = "cache_path" } public static let fileName = ".iblinter.yml" @@ -53,6 +55,7 @@ public struct Config: Codable { reporter = "xcode" disableWhileBuildingForIB = true ignoreCache = false + cachePath = nil } init(disabledRules: [String] = [], enabledRules: [String] = [], @@ -63,7 +66,7 @@ public struct Config: Codable { useTraitCollectionsRule: UseTraitCollectionsConfig? = nil, hidesBottomBarRule: HidesBottomBarConfig? = nil, reporter: String = "xcode", disableWhileBuildingForIB: Bool = true, - ignoreCache: Bool = false) { + ignoreCache: Bool = false, cachePath: String? = nil) { self.disabledRules = disabledRules self.enabledRules = enabledRules self.excluded = excluded @@ -76,6 +79,7 @@ public struct Config: Codable { self.reporter = reporter self.disableWhileBuildingForIB = disableWhileBuildingForIB self.ignoreCache = ignoreCache + self.cachePath = cachePath } public init(from decoder: Decoder) throws { diff --git a/Sources/IBLinterKit/Utils/LintCache.swift b/Sources/IBLinterKit/Utils/LintCache.swift index 6443909..403c905 100644 --- a/Sources/IBLinterKit/Utils/LintCache.swift +++ b/Sources/IBLinterKit/Utils/LintCache.swift @@ -22,13 +22,13 @@ struct LintEmptyCache: LintCache { } protocol CacheFileManager { - var cacheDir: URL { get } + var defaultCacheDir: URL { get } func modificationDate(for path: String) -> Date? - func createCacheDirectory() throws + func createDirectory(at path: URL) throws } extension FileManager: CacheFileManager { - var cacheDir: URL { + var defaultCacheDir: URL { return urls(for: .cachesDirectory, in: .userDomainMask)[0] .appendingPathComponent("IBLinter/\(Version.current.value)") } @@ -37,8 +37,8 @@ extension FileManager: CacheFileManager { return (try? attributesOfItem(atPath: path))?[.modificationDate] as? Date } - func createCacheDirectory() throws { - try createDirectory(at: cacheDir, withIntermediateDirectories: true, attributes: nil) + func createDirectory(at path: URL) throws { + try createDirectory(at: path, withIntermediateDirectories: true, attributes: nil) } } @@ -46,11 +46,14 @@ public class LintDiskCache: LintCache { var content: LintCacheContent let fileManager: CacheFileManager let configHashKey: String + let cacheDir: URL - fileprivate init(content: LintCacheContent, fileManager: CacheFileManager, configHashKey: String) { + fileprivate init(content: LintCacheContent, fileManager: CacheFileManager, + configHashKey: String, cacheDir: URL) { self.content = content self.fileManager = fileManager self.configHashKey = configHashKey + self.cacheDir = cacheDir } public func insertCache(for fileURL: URL, violations: [Violation]) { @@ -71,18 +74,28 @@ public class LintDiskCache: LintCache { extension LintDiskCache { + static func deriveCacheDir(from config: Config, fileManager: CacheFileManager) -> URL { + return config.cachePath.flatMap { URL(fileURLWithPath: $0) } ?? fileManager.defaultCacheDir + } + static func new(with fileManager: CacheFileManager, config: Config) throws -> LintCache { let emptyContent = LintCacheContent(entries: [:]) let hashKey = try cacheHashKey(for: config) - return LintDiskCache(content: emptyContent, fileManager: fileManager, configHashKey: hashKey) + return LintDiskCache(content: emptyContent, fileManager: fileManager, configHashKey: hashKey, + cacheDir: Self.deriveCacheDir(from: config, fileManager: fileManager)) } static func load(with fileManager: CacheFileManager, config: Config) throws -> LintCache { let hashKey = try cacheHashKey(for: config) - let cacheFilePath = fileManager.cacheDir.appendingPathComponent(hashKey) + let cacheDir = Self.deriveCacheDir(from: config, fileManager: fileManager) + let cacheFilePath = cacheDir.appendingPathComponent(hashKey) let cacheFileContent = try Data(contentsOf: cacheFilePath) let content = try JSONDecoder().decode(LintCacheContent.self, from: cacheFileContent) - return LintDiskCache(content: content, fileManager: fileManager, configHashKey: hashKey) + return LintDiskCache( + content: content, fileManager: fileManager, + configHashKey: hashKey, + cacheDir: cacheDir + ) } private static func cacheHashKey(for config: Config) throws -> String { @@ -94,9 +107,9 @@ extension LintDiskCache { } public func save() throws { - let cacheFilePath = fileManager.cacheDir.appendingPathComponent(configHashKey) + let cacheFilePath = cacheDir.appendingPathComponent(configHashKey) let contentData = try JSONEncoder().encode(content) - try fileManager.createCacheDirectory() + try fileManager.createDirectory(at: cacheDir) try contentData.write(to: cacheFilePath) } } diff --git a/Tests/IBLinterKitTest/Utils/LintCacheTests.swift b/Tests/IBLinterKitTest/Utils/LintCacheTests.swift index 8dda8cb..abf81e1 100644 --- a/Tests/IBLinterKitTest/Utils/LintCacheTests.swift +++ b/Tests/IBLinterKitTest/Utils/LintCacheTests.swift @@ -2,19 +2,44 @@ import XCTest class LintCacheTests: XCTestCase { + class MockFileManager: CacheFileManager { + let fixture = Fixture() + lazy var defaultCacheDir = makeTemporalyDirectory() + func modificationDate(for path: String) -> Date? { + return Date(timeIntervalSinceReferenceDate: 0.0) + } - func testLoadDiskCache() throws { - class MockFileManager: CacheFileManager { - let fixture = Fixture() - var cacheDir: URL { - return URL(fileURLWithPath: NSTemporaryDirectory()) - } - func modificationDate(for path: String) -> Date? { - return Date(timeIntervalSinceReferenceDate: 0.0) - } - - func createCacheDirectory() throws {} + func createDirectory(at path: URL) throws { + try FileManager.default.createDirectory(at: path) } + } + + func testCacheDirOption() throws { + let tmpDir = makeTemporalyDirectory() + let overrideCacheDir = tmpDir.appendingPathComponent("override") + let config = Config(cachePath: overrideCacheDir.path) + let fileManager = MockFileManager() + fileManager.defaultCacheDir = tmpDir.appendingPathComponent("default") + let cacheDir = LintDiskCache.deriveCacheDir(from: config, fileManager: fileManager) + XCTAssertEqual(cacheDir, overrideCacheDir) + + let cache = try LintDiskCache.new(with: fileManager, config: config) + XCTAssertFalse( + FileManager.default.fileExists(atPath: fileManager.defaultCacheDir.path) + ) + XCTAssertFalse( + FileManager.default.fileExists(atPath: overrideCacheDir.path) + ) + try cache.save() + XCTAssertFalse( + FileManager.default.fileExists(atPath: fileManager.defaultCacheDir.path) + ) + XCTAssertTrue( + FileManager.default.fileExists(atPath: overrideCacheDir.path) + ) + } + + func testLoadDiskCache() throws { let config = Config() let mockFileManager = MockFileManager() let cache = try LintDiskCache.new(with: mockFileManager, config: config) @@ -32,3 +57,13 @@ class LintCacheTests: XCTestCase { XCTAssertEqual(restoredViolations?[0].message, "Warning message") } } + +func makeTemporalyDirectory() -> URL { + let tempdir = URL(fileURLWithPath: NSTemporaryDirectory()) + let templatePath = tempdir.appendingPathComponent("iblinter.XXXXXX") + var template = [UInt8](templatePath.path.utf8).map({ Int8($0) }) + [Int8(0)] + if mkdtemp(&template) == nil { + fatalError("Failed to create temp directory") + } + return URL(fileURLWithPath: String(cString: template)) +} From 1001b78be5a838a00daf6c70c66c2eb58c7cc52b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 5 Oct 2022 01:05:27 +0000 Subject: [PATCH 3/3] Make swiftlint happy :) --- Sources/IBLinterKit/Utils/Glob.swift | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Sources/IBLinterKit/Utils/Glob.swift b/Sources/IBLinterKit/Utils/Glob.swift index ac5b85e..4630ddf 100644 --- a/Sources/IBLinterKit/Utils/Glob.swift +++ b/Sources/IBLinterKit/Utils/Glob.swift @@ -42,17 +42,15 @@ public final class Glob { let patterns = expandRecursiveStars(pattern: pattern) var results: [String] = [] - for pattern in patterns { - if executeGlob(pattern: pattern, gt: >) { - #if os(Linux) - let matchCount = Int(gt.gl_pathc) - #else - let matchCount = Int(gt.gl_matchc) - #endif - for i in 0..