Move the event mask into a platform-neutral product
`InotifyEventMask` took its bits from the C header, so nothing that imported it could build outside Linux. The new `InotifyMask` product spells out the kernel constants instead; a Linux test compares each of them with the header. `Inotify` re-exports the module, so existing code is unaffected.
This commit is contained in:
+7
-1
@@ -8,7 +8,11 @@ let package = Package(
|
|||||||
.library(
|
.library(
|
||||||
name: "Inotify",
|
name: "Inotify",
|
||||||
targets: ["Inotify"]
|
targets: ["Inotify"]
|
||||||
)
|
),
|
||||||
|
.library(
|
||||||
|
name: "InotifyMask",
|
||||||
|
targets: ["InotifyMask"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.7.1"),
|
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.7.1"),
|
||||||
@@ -20,10 +24,12 @@ let package = Package(
|
|||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.systemLibrary(name: "CInotify"),
|
.systemLibrary(name: "CInotify"),
|
||||||
|
.target(name: "InotifyMask"),
|
||||||
.target(
|
.target(
|
||||||
name: "Inotify",
|
name: "Inotify",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"CInotify",
|
"CInotify",
|
||||||
|
"InotifyMask",
|
||||||
.product(name: "Logging", package: "swift-log"),
|
.product(name: "Logging", package: "swift-log"),
|
||||||
.product(name: "_NIOFileSystem", package: "swift-nio"),
|
.product(name: "_NIOFileSystem", package: "swift-nio"),
|
||||||
.product(name: "SystemPackage", package: "swift-system")
|
.product(name: "SystemPackage", package: "swift-system")
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ Use `isExcluded(_:)` to check whether a name is currently on the exclusion list.
|
|||||||
|
|
||||||
`InotifyEventMask` is an `OptionSet` that mirrors the native inotify flags. You can combine them freely.
|
`InotifyEventMask` is an `OptionSet` that mirrors the native inotify flags. You can combine them freely.
|
||||||
|
|
||||||
|
The mask lives in the separate `InotifyMask` product, which has no Linux dependency. Depend on it alone where code only stores or compares masks and must build or be tested on other platforms; `Inotify` re-exports it.
|
||||||
|
|
||||||
| Mask | Description |
|
| Mask | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `.access` | File was read |
|
| `.access` | File was read |
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// The mask lives in its own module so that it is usable off Linux; users
|
||||||
|
// of `Inotify` keep seeing it as before.
|
||||||
|
@_exported import InotifyMask
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import CInotify
|
|
||||||
|
|
||||||
public struct InotifyEventMask: OptionSet, Sendable, Hashable {
|
|
||||||
public let rawValue: CUnsignedInt
|
|
||||||
|
|
||||||
public init(rawValue: UInt32) {
|
|
||||||
self.rawValue = rawValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Watchable Events
|
|
||||||
|
|
||||||
public static let access = InotifyEventMask(rawValue: CUnsignedInt(IN_ACCESS))
|
|
||||||
public static let attrib = InotifyEventMask(rawValue: CUnsignedInt(IN_ATTRIB))
|
|
||||||
public static let closeWrite = InotifyEventMask(rawValue: CUnsignedInt(IN_CLOSE_WRITE))
|
|
||||||
public static let closeNoWrite = InotifyEventMask(rawValue: CUnsignedInt(IN_CLOSE_NOWRITE))
|
|
||||||
public static let create = InotifyEventMask(rawValue: CUnsignedInt(IN_CREATE))
|
|
||||||
public static let delete = InotifyEventMask(rawValue: CUnsignedInt(IN_DELETE))
|
|
||||||
public static let deleteSelf = InotifyEventMask(rawValue: CUnsignedInt(IN_DELETE_SELF))
|
|
||||||
public static let modify = InotifyEventMask(rawValue: CUnsignedInt(IN_MODIFY))
|
|
||||||
public static let moveSelf = InotifyEventMask(rawValue: CUnsignedInt(IN_MOVE_SELF))
|
|
||||||
public static let movedFrom = InotifyEventMask(rawValue: CUnsignedInt(IN_MOVED_FROM))
|
|
||||||
public static let movedTo = InotifyEventMask(rawValue: CUnsignedInt(IN_MOVED_TO))
|
|
||||||
public static let open = InotifyEventMask(rawValue: CUnsignedInt(IN_OPEN))
|
|
||||||
|
|
||||||
// MARK: - Combinations
|
|
||||||
|
|
||||||
public static let move: InotifyEventMask = [.movedFrom, .movedTo]
|
|
||||||
public static let close: InotifyEventMask = [.closeWrite, .closeNoWrite]
|
|
||||||
public static let allEvents: InotifyEventMask = [
|
|
||||||
.access, .attrib, .closeWrite, .closeNoWrite,
|
|
||||||
.create, .delete, .deleteSelf, .modify,
|
|
||||||
.moveSelf, .movedFrom, .movedTo, .open
|
|
||||||
]
|
|
||||||
|
|
||||||
// MARK: - Watch Flags
|
|
||||||
|
|
||||||
public static let dontFollow = InotifyEventMask(rawValue: CUnsignedInt(IN_DONT_FOLLOW))
|
|
||||||
public static let onlyDir = InotifyEventMask(rawValue: CUnsignedInt(IN_ONLYDIR))
|
|
||||||
public static let oneShot = InotifyEventMask(rawValue: CUnsignedInt(IN_ONESHOT))
|
|
||||||
|
|
||||||
// MARK: - Kernel-Only Flags
|
|
||||||
|
|
||||||
public static let isDir = InotifyEventMask(rawValue: CUnsignedInt(IN_ISDIR))
|
|
||||||
public static let ignored = InotifyEventMask(rawValue: CUnsignedInt(IN_IGNORED))
|
|
||||||
public static let queueOverflow = InotifyEventMask(rawValue: CUnsignedInt(IN_Q_OVERFLOW))
|
|
||||||
public static let unmount = InotifyEventMask(rawValue: CUnsignedInt(IN_UNMOUNT))
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/// The events and flags of an inotify watch or event, as bits.
|
||||||
|
///
|
||||||
|
/// The values are the constants of the Linux `<sys/inotify.h>` header,
|
||||||
|
/// which are part of the kernel's stable interface. Spelling them out here
|
||||||
|
/// keeps this module free of the C header, so it builds on every platform
|
||||||
|
/// and lets code that only stores or compares masks be tested off Linux.
|
||||||
|
public struct InotifyEventMask: OptionSet, Sendable, Hashable {
|
||||||
|
public let rawValue: UInt32
|
||||||
|
|
||||||
|
public init(rawValue: UInt32) {
|
||||||
|
self.rawValue = rawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Watchable Events
|
||||||
|
|
||||||
|
public static let access = InotifyEventMask(rawValue: 0x0000_0001)
|
||||||
|
public static let modify = InotifyEventMask(rawValue: 0x0000_0002)
|
||||||
|
public static let attrib = InotifyEventMask(rawValue: 0x0000_0004)
|
||||||
|
public static let closeWrite = InotifyEventMask(rawValue: 0x0000_0008)
|
||||||
|
public static let closeNoWrite = InotifyEventMask(rawValue: 0x0000_0010)
|
||||||
|
public static let open = InotifyEventMask(rawValue: 0x0000_0020)
|
||||||
|
public static let movedFrom = InotifyEventMask(rawValue: 0x0000_0040)
|
||||||
|
public static let movedTo = InotifyEventMask(rawValue: 0x0000_0080)
|
||||||
|
public static let create = InotifyEventMask(rawValue: 0x0000_0100)
|
||||||
|
public static let delete = InotifyEventMask(rawValue: 0x0000_0200)
|
||||||
|
public static let deleteSelf = InotifyEventMask(rawValue: 0x0000_0400)
|
||||||
|
public static let moveSelf = InotifyEventMask(rawValue: 0x0000_0800)
|
||||||
|
|
||||||
|
// MARK: - Combinations
|
||||||
|
|
||||||
|
public static let move: InotifyEventMask = [.movedFrom, .movedTo]
|
||||||
|
public static let close: InotifyEventMask = [.closeWrite, .closeNoWrite]
|
||||||
|
public static let allEvents: InotifyEventMask = [
|
||||||
|
.access, .attrib, .closeWrite, .closeNoWrite,
|
||||||
|
.create, .delete, .deleteSelf, .modify,
|
||||||
|
.moveSelf, .movedFrom, .movedTo, .open,
|
||||||
|
]
|
||||||
|
|
||||||
|
// MARK: - Watch Flags
|
||||||
|
|
||||||
|
public static let onlyDir = InotifyEventMask(rawValue: 0x0100_0000)
|
||||||
|
public static let dontFollow = InotifyEventMask(rawValue: 0x0200_0000)
|
||||||
|
public static let oneShot = InotifyEventMask(rawValue: 0x8000_0000)
|
||||||
|
|
||||||
|
// MARK: - Kernel-Only Flags
|
||||||
|
|
||||||
|
public static let unmount = InotifyEventMask(rawValue: 0x0000_2000)
|
||||||
|
public static let queueOverflow = InotifyEventMask(rawValue: 0x0000_4000)
|
||||||
|
public static let ignored = InotifyEventMask(rawValue: 0x0000_8000)
|
||||||
|
public static let isDir = InotifyEventMask(rawValue: 0x4000_0000)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import CInotify
|
||||||
|
import Testing
|
||||||
|
@testable import Inotify
|
||||||
|
|
||||||
|
@Suite("Event Mask")
|
||||||
|
struct EventMaskTests {
|
||||||
|
@Test(arguments: [
|
||||||
|
(InotifyEventMask.access, UInt32(IN_ACCESS)),
|
||||||
|
(.attrib, UInt32(IN_ATTRIB)),
|
||||||
|
(.closeWrite, UInt32(IN_CLOSE_WRITE)),
|
||||||
|
(.closeNoWrite, UInt32(IN_CLOSE_NOWRITE)),
|
||||||
|
(.create, UInt32(IN_CREATE)),
|
||||||
|
(.delete, UInt32(IN_DELETE)),
|
||||||
|
(.deleteSelf, UInt32(IN_DELETE_SELF)),
|
||||||
|
(.modify, UInt32(IN_MODIFY)),
|
||||||
|
(.moveSelf, UInt32(IN_MOVE_SELF)),
|
||||||
|
(.movedFrom, UInt32(IN_MOVED_FROM)),
|
||||||
|
(.movedTo, UInt32(IN_MOVED_TO)),
|
||||||
|
(.open, UInt32(IN_OPEN)),
|
||||||
|
(.dontFollow, UInt32(IN_DONT_FOLLOW)),
|
||||||
|
(.onlyDir, UInt32(IN_ONLYDIR)),
|
||||||
|
(.oneShot, UInt32(IN_ONESHOT)),
|
||||||
|
(.isDir, UInt32(IN_ISDIR)),
|
||||||
|
(.ignored, UInt32(IN_IGNORED)),
|
||||||
|
(.queueOverflow, UInt32(IN_Q_OVERFLOW)),
|
||||||
|
(.unmount, UInt32(IN_UNMOUNT)),
|
||||||
|
] as [(InotifyEventMask, UInt32)])
|
||||||
|
func matchesTheKernelConstant(mask: InotifyEventMask, constant: UInt32) {
|
||||||
|
#expect(mask.rawValue == constant)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user