Implement recursive watching of a directory
This commit is contained in:
44
Sources/Inotify/DirectoryResolver.swift
Normal file
44
Sources/Inotify/DirectoryResolver.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
import _NIOFileSystem
|
||||
|
||||
public struct DirectoryResolver {
|
||||
static let fileManager = FileSystem.shared
|
||||
|
||||
public static func resolve(_ paths: String...) async throws -> [FilePath] {
|
||||
try await Self.resolve(paths)
|
||||
}
|
||||
|
||||
static func resolve(_ paths: [String]) async throws -> [FilePath] {
|
||||
var resolved: [FilePath] = []
|
||||
|
||||
for path in paths {
|
||||
let itemPath = FilePath(path)
|
||||
try await Self.ensure(itemPath, is: .directory)
|
||||
|
||||
let allDirectoriesIncludingSelf = try await getAllSubdirectoriesAndSelf(at: itemPath)
|
||||
resolved.append(contentsOf: allDirectoriesIncludingSelf)
|
||||
}
|
||||
|
||||
return resolved
|
||||
}
|
||||
|
||||
private static func ensure(_ path: FilePath, is fileType: FileType) async throws {
|
||||
guard let fileInfo = try await fileManager.info(forFileAt: path) else {
|
||||
throw DirectoryResolverError.pathNotFound(path)
|
||||
}
|
||||
|
||||
guard fileInfo.type == fileType else {
|
||||
throw DirectoryResolverError.pathIsNoDirectory(path)
|
||||
}
|
||||
}
|
||||
|
||||
private static func getAllSubdirectoriesAndSelf(at path: FilePath) async throws -> [FilePath] {
|
||||
var result: [FilePath] = []
|
||||
let directoryHandle = try await fileManager.openDirectory(atPath: path)
|
||||
for try await childContent in directoryHandle.listContents(recursive: true) {
|
||||
guard childContent.type == .directory else { continue }
|
||||
result.append(childContent.path)
|
||||
}
|
||||
try await directoryHandle.close()
|
||||
return result
|
||||
}
|
||||
}
|
||||
16
Sources/Inotify/DirectoryResolverErrror.swift
Normal file
16
Sources/Inotify/DirectoryResolverErrror.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
import Foundation
|
||||
import SystemPackage
|
||||
|
||||
public enum DirectoryResolverError: LocalizedError, Equatable {
|
||||
case pathNotFound(FilePath)
|
||||
case pathIsNoDirectory(FilePath)
|
||||
|
||||
var errorDescription: String {
|
||||
switch self {
|
||||
case .pathNotFound(let path):
|
||||
return "Path not found: \(path)"
|
||||
case .pathIsNoDirectory(let path):
|
||||
return "Path is not a directory: \(path)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,17 @@ public actor Inotify {
|
||||
return wd
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func addRecursiveWatch(forDirectory path: String, mask: InotifyEventMask) async throws -> [CInt] {
|
||||
let directoryPaths = try await DirectoryResolver.resolve(path)
|
||||
var result: [CInt] = []
|
||||
for path in directoryPaths {
|
||||
let wd = try self.addWatch(path: path.string, mask: mask)
|
||||
result.append(wd)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func removeWatch(_ wd: CInt) throws {
|
||||
guard inotify_rm_watch(self.fd, wd) == 0 else {
|
||||
throw InotifyError.removeWatchFailed(watchDescriptor: wd, errno: cinotify_get_errno())
|
||||
|
||||
Reference in New Issue
Block a user