Skip to content

Commit

Permalink
Merge branch 'feature/document-with-docc' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethlaskoski committed Apr 12, 2022
2 parents 75f88e2 + 00e31c9 commit 9529234
Show file tree
Hide file tree
Showing 58 changed files with 627 additions and 102 deletions.
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,3 @@
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
_site
.sass-cache
.jekyll-cache
.jekyll-metadata
vendor
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.3
// swift-tools-version: 5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
Expand Down
4 changes: 2 additions & 2 deletions Playgrounds/FileSystemEvent.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ let tmpURL = FileManager.default.temporaryDirectory
let url = URL(fileURLWithPath: "\(id)", relativeTo: tmpURL)
let tmp = try! FileDescriptor.open(tmpURL.path, .readOnly, options: .eventOnly)

var received = DispatchSource.FileSystemEvent()
var received = FileSystemEventPublisher.Event()

print(received) // prints "FileSystemEvent(rawValue: 0)"

let cancellable = DispatchSource.publish(at: tmp)
let cancellable = FileSystemEventPublisher.monitor(tmp, for: .all)
.sink { event in
received = event
}
Expand Down
38 changes: 15 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
# FileSystemEventPublisher
A publisher that emits events in the file system.

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fkennethlaskoski%2FFileSystemEventPublisher%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/kennethlaskoski/FileSystemEventPublisher)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fkennethlaskoski%2FFileSystemEventPublisher%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/kennethlaskoski/FileSystemEventPublisher)
# ``FileSystemEventPublisher``

A publisher that emits events in the file system.

## Example usage:
## Overview

```
let id = UUID()
let tmpURL = FileManager.default.temporaryDirectory
let url = URL(fileURLWithPath: "\(id)", relativeTo: tmpURL)
let tmp = try! FileDescriptor.open(tmpURL.path, .readOnly, options: .eventOnly)
The FileSystemEventPublisher framework wraps a [Combine Publisher](https://developer.apple.com/documentation/combine/publisher)
around a [DispatchSourceFileSystemObject](https://developer.apple.com/documentation/dispatch/dispatchsourcefilesystemobject),
providing a modern high-level interface to an efficient way of monitoring filesystem events.

var received = DispatchSource.FileSystemEvent()
## Usage

print(received) // prints "FileSystemEvent(rawValue: 0)"
A typealias and a function are all the exposed interface, the Combine framework provides all remaining functionality.

let cancellable = DispatchSource.publish(at: tmp)
.sink { event in
received = event
}
The publisher is created by a function with two parameters: a file and a set of events; this signature reflects the
underlying DispatchSource interface and was adopted for it's simplicity and performance.

try! FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil)
sleep(1)
The first parameter is a mask containing events of interest. The set of events are defined by a typealias to
[DispatchSoutce.FileSystemEvent](https://developer.apple.com/documentation/dispatch/dispatchsource/filesystemevent).
This type is also the Output of the created publisher, i.e., the type of values to be delivered to subscribers.

print(received) // prints "FileSystemEvent(rawValue: 18)"
The second parameter is a [FileDescriptor](https://developer.apple.com/documentation/system/filedescriptor) pointing to an open file, folder or socket.

cancellable.cancel()
```
The package includes a playground with a short example code.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ``FileSystemEventPublisher``

A publisher that emits events in the file system.

## Overview

The FileSystemEventPublisher framework wraps a [Combine Publisher](https://developer.apple.com/documentation/combine/publisher)
around a [DispatchSourceFileSystemObject](https://developer.apple.com/documentation/dispatch/dispatchsourcefilesystemobject),
providing a modern high-level interface to an efficient way of monitoring filesystem events.

## Usage

A typealias and a function are all the exposed interface, the Combine framework provides all remaining functionality.

The publisher is created by a function with two parameters: a file and a set of events; this signature reflects the
underlying DispatchSource interface and was adopted for it's simplicity and performance.

The first parameter is a mask containing events of interest. The set of events are defined by a typealias to
[DispatchSoutce.FileSystemEvent](https://developer.apple.com/documentation/dispatch/dispatchsource/filesystemevent).
This type is also the Output of the created publisher, i.e., the type of values to be delivered to subscribers.

The second parameter is a [FileDescriptor](https://developer.apple.com/documentation/system/filedescriptor) pointing to an open file, folder or socket.

## Topics

### Values

- ``Event``

### Creating a publisher

- ``monitor(_:for:)``
126 changes: 63 additions & 63 deletions Sources/FileSystemEventPublisher/FileSystemEventPublisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,82 @@ import System
import Combine
import Foundation

@available(macOS 11.0, iOS 14.0, *)
private extension DispatchSource {
///
/// Events involving a change to a file system object.
///
public typealias Event = DispatchSource.FileSystemEvent

/// A publisher that emits events in the file system.
struct FileSystemEventPublisher: Publisher {
private static let queue = DispatchQueue(
label: "br.com.tractrix.FileSystemEventPublisher",
qos: .userInitiated,
attributes: .concurrent
)
///
/// Creates a new publisher for monitoring file system events.
///
/// - Parameters:
/// - fileDescriptor: A file descriptor pointing to an open file or socket.
/// - eventMask: The set of events you want to monitor. For a list of possible values,
/// see [DispatchSource.FileSystemEvent](https://developer.apple.com/documentation/dispatch/dispatchsource/filesystemevent).
///
/// - Returns: A publisher that emits events occurring at the observed file.
///
public func monitor(_ fileDescriptor: FileDescriptor, for eventMask: Event) -> AnyPublisher<Event, Never> {
FileSystemMonitor(fileDescriptor, for: eventMask).eraseToAnyPublisher()
}

typealias Output = FileSystemEvent
typealias Failure = Never
//@available(macOS 11.0, iOS 14.0, *)

private let file: FileDescriptor
private let mask: FileSystemEvent
/// A publisher that emits events in the file system.
private struct FileSystemMonitor: Publisher {
typealias Output = Event
typealias Failure = Never

init(of eventMask: FileSystemEvent, at fileDescriptor: FileDescriptor) {
file = fileDescriptor
mask = eventMask
}
private static let queue = DispatchQueue(
label: "br.dev.sr.FileSystemEventPublisher",
qos: .userInitiated,
attributes: .concurrent
)

func receive<S>(subscriber: S) where S: Subscriber, S.Failure == Never, S.Input == FileSystemEvent {
let subscription = Subscription<S>(of: mask, at: file, on: FileSystemEventPublisher.queue)
subscription.target = subscriber
subscriber.receive(subscription: subscription)
}
private let file: FileDescriptor
private let mask: Event

init(_ fileDescriptor: FileDescriptor, for eventMask: Event) {
file = fileDescriptor
mask = eventMask
}

/// The subscription to receive file system events
final class Subscription<Target: Subscriber>: Combine.Subscription where Target.Input == FileSystemEvent {
var target: Target?
func receive<S>(subscriber: S) where S: Subscriber, S.Failure == Never, S.Input == Event {
let subscription = Subscription<S>(of: mask, at: file, on: FileSystemMonitor.queue)
subscription.target = subscriber
subscriber.receive(subscription: subscription)
}
}

private var source: DispatchSourceFileSystemObject!
init(of events: FileSystemEvent, at file: FileDescriptor, on queue: DispatchQueue) {
source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: file.rawValue,
eventMask: events,
queue: queue
)
source.setEventHandler {
self.trigger(event: self.source.data)
}
source.setCancelHandler {
try? file.close()
self.source = nil
}
source.resume()
}
/// The subscription to receive file system events
private final class Subscription<Target: Subscriber>: Combine.Subscription where Target.Input == Event {
var target: Target?

func request(_ demand: Subscribers.Demand) {}
private var source: DispatchSourceFileSystemObject!
private func trigger(event: Event) {
_ = target?.receive(event)
}

func cancel() {
target = nil
source.cancel()
init(of events: Event, at file: FileDescriptor, on queue: DispatchQueue) {
source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: file.rawValue,
eventMask: events,
queue: queue
)
source.setEventHandler {
self.trigger(event: self.source.data)
}

func trigger(event: FileSystemEvent) {
_ = target?.receive(event)
source.setCancelHandler {
try? file.close()
self.source = nil
}
source.resume()
}
}

@available(macOS 11.0, iOS 14.0, *)
extension DispatchSource {
///
/// Creates a new publisher for monitoring file system events.
///
/// - Parameters:
/// - eventMask: The set of events you want to monitor. For a list of possible values,
/// see [DispatchSource.FileSystemEvent](https://developer.apple.com/documentation/dispatch/dispatchsource/filesystemevent).
/// - fileDescriptor: A file descriptor pointing to an open file or socket.
///
/// - Returns: A publisher that emits events occurring at the observed file.
///
public static func publish(_ eventMask: FileSystemEvent = .all, at fileDescriptor: FileDescriptor) -> AnyPublisher<FileSystemEvent, Never> {
FileSystemEventPublisher(of: eventMask, at: fileDescriptor).eraseToAnyPublisher()
func request(_ demand: Subscribers.Demand) {}

func cancel() {
target = nil
source.cancel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ final class FileSystemEventPublisherTests: XCTestCase {
let url = URL(fileURLWithPath: "\(id)", relativeTo: tmpURL)
let tmp = try! FileDescriptor.open(tmpURL.path, .readOnly, options: .eventOnly)

var received = DispatchSource.FileSystemEvent()
XCTAssertTrue(received.isEmpty)
var event = Event()
XCTAssertTrue(event.isEmpty)

let expectation = self.expectation(description: "receive")
let cancellable = DispatchSource.publish(at: tmp)
.sink { event in
received = event
let expectation = self.expectation(description: "Receive filesystem event")
let cancellable = monitor(tmp, for: .all)
.sink {
event = $0
expectation.fulfill()
}

XCTAssertNoThrow(try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil))
waitForExpectations(timeout: 0.01)
waitForExpectations(timeout: Double.leastNonzeroMagnitude)

XCTAssertTrue(received.contains(.write))
XCTAssertTrue(event.contains(.write))

cancellable.cancel()
}
Expand Down
9 changes: 9 additions & 0 deletions docs/css/documentation-topic.de084985.css

Large diffs are not rendered by default.

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/css/index.47bc740e.css

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/css/topic.2eb01958.css

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/css/tutorials-overview.8754eb09.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/data/documentation/filesystemeventpublisher.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"primaryContentSections":[{"kind":"content","content":[{"anchor":"Overview","level":2,"type":"heading","text":"Overview"},{"type":"paragraph","inlineContent":[{"type":"text","text":"The FileSystemEventPublisher framework wraps a "},{"type":"reference","isActive":true,"identifier":"https:\/\/developer.apple.com\/documentation\/combine\/publisher"},{"type":"text","text":" "},{"type":"text","text":"around a "},{"type":"reference","isActive":true,"identifier":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsourcefilesystemobject"},{"type":"text","text":","},{"type":"text","text":" "},{"type":"text","text":"providing a modern high-level interface to an efficient way of monitoring filesystem events."}]},{"anchor":"Usage","level":2,"type":"heading","text":"Usage"},{"type":"paragraph","inlineContent":[{"type":"text","text":"A typealias and a function are all the exposed interface, the Combine framework provides all remaining functionality."}]},{"type":"paragraph","inlineContent":[{"type":"text","text":"The publisher is created by a function with two parameters: a file and a set of events; this signature reflects the"},{"type":"text","text":" "},{"type":"text","text":"underlying DispatchSource interface and was adopted for it’s simplicity and performance."}]},{"type":"paragraph","inlineContent":[{"type":"text","text":"The first parameter is a mask containing events of interest. The set of events are defined by a typealias to"},{"type":"text","text":" "},{"type":"reference","isActive":true,"identifier":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsource\/filesystemevent"},{"type":"text","text":"."},{"type":"text","text":" "},{"type":"text","text":"This type is also the Output of the created publisher, i.e., the type of values to be delivered to subscribers."}]},{"type":"paragraph","inlineContent":[{"type":"text","text":"The second parameter is a "},{"type":"reference","isActive":true,"identifier":"https:\/\/developer.apple.com\/documentation\/system\/filedescriptor"},{"type":"text","text":" pointing to an open file, folder or socket."}]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/filesystemeventpublisher"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"A publisher that emits events in the file system."}],"kind":"symbol","metadata":{"roleHeading":"Framework","externalID":"FileSystemEventPublisher","title":"FileSystemEventPublisher","symbolKind":"module","role":"collection","modules":[{"name":"FileSystemEventPublisher"}]},"hierarchy":{"paths":[[]]},"topicSections":[{"title":"Values","identifiers":["doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/Event"]},{"title":"Creating a publisher","identifiers":["doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/monitor(_:for:)"]}],"references":{"https://developer.apple.com/documentation/system/filedescriptor":{"title":"FileDescriptor","titleInlineContent":[{"type":"text","text":"FileDescriptor"}],"type":"link","identifier":"https:\/\/developer.apple.com\/documentation\/system\/filedescriptor","url":"https:\/\/developer.apple.com\/documentation\/system\/filedescriptor"},"doc://FileSystemEventPublisher/documentation/FileSystemEventPublisher/Event":{"role":"symbol","title":"Event","fragments":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"Event"}],"abstract":[{"type":"text","text":"Events involving a change to a file system object."}],"identifier":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/Event","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"Event"}],"url":"\/documentation\/filesystemeventpublisher\/event"},"doc://FileSystemEventPublisher/documentation/FileSystemEventPublisher/monitor(_:for:)":{"role":"symbol","title":"monitor(_:for:)","fragments":[{"kind":"keyword","text":"func"},{"kind":"text","text":" "},{"kind":"identifier","text":"monitor"},{"kind":"text","text":"("},{"kind":"typeIdentifier","text":"FileDescriptor","preciseIdentifier":"s:6System14FileDescriptorV"},{"kind":"text","text":", "},{"kind":"externalParam","text":"for"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Event","preciseIdentifier":"s:24FileSystemEventPublisher0C0a"},{"kind":"text","text":") -> "},{"kind":"typeIdentifier","text":"AnyPublisher","preciseIdentifier":"s:7Combine12AnyPublisherV"},{"kind":"text","text":"<"},{"kind":"typeIdentifier","text":"Event","preciseIdentifier":"s:24FileSystemEventPublisher0C0a"},{"kind":"text","text":", "},{"kind":"typeIdentifier","text":"Never","preciseIdentifier":"s:s5NeverO"},{"kind":"text","text":">"}],"abstract":[{"type":"text","text":"Creates a new publisher for monitoring file system events."}],"identifier":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/monitor(_:for:)","kind":"symbol","type":"topic","url":"\/documentation\/filesystemeventpublisher\/monitor(_:for:)"},"doc://FileSystemEventPublisher/documentation/FileSystemEventPublisher":{"role":"collection","title":"FileSystemEventPublisher","abstract":[{"type":"text","text":"A publisher that emits events in the file system."}],"identifier":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher","kind":"symbol","type":"topic","url":"\/documentation\/filesystemeventpublisher"},"https://developer.apple.com/documentation/dispatch/dispatchsource/filesystemevent":{"title":"DispatchSoutce.FileSystemEvent","titleInlineContent":[{"type":"text","text":"DispatchSoutce.FileSystemEvent"}],"type":"link","identifier":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsource\/filesystemevent","url":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsource\/filesystemevent"},"https://developer.apple.com/documentation/dispatch/dispatchsourcefilesystemobject":{"title":"DispatchSourceFileSystemObject","titleInlineContent":[{"type":"text","text":"DispatchSourceFileSystemObject"}],"type":"link","identifier":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsourcefilesystemobject","url":"https:\/\/developer.apple.com\/documentation\/dispatch\/dispatchsourcefilesystemobject"},"https://developer.apple.com/documentation/combine/publisher":{"title":"Combine Publisher","titleInlineContent":[{"type":"text","text":"Combine Publisher"}],"type":"link","identifier":"https:\/\/developer.apple.com\/documentation\/combine\/publisher","url":"https:\/\/developer.apple.com\/documentation\/combine\/publisher"}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"Event"},{"kind":"text","text":" = "},{"kind":"typeIdentifier","text":"DispatchSource","preciseIdentifier":"c:objc(cs)OS_dispatch_source"},{"kind":"text","text":"."},{"kind":"typeIdentifier","text":"FileSystemEvent","preciseIdentifier":"s:So18OS_dispatch_sourceC8DispatchE15FileSystemEventV"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/filesystemeventpublisher\/event"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/Event","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"Events involving a change to a file system object."}],"kind":"symbol","metadata":{"fragments":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"Event"}],"title":"Event","roleHeading":"Type Alias","role":"symbol","symbolKind":"typealias","externalID":"s:24FileSystemEventPublisher0C0a","modules":[{"name":"FileSystemEventPublisher"}],"navigatorTitle":[{"kind":"identifier","text":"Event"}]},"hierarchy":{"paths":[["doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher"]]},"references":{"doc://FileSystemEventPublisher/documentation/FileSystemEventPublisher/Event":{"role":"symbol","title":"Event","fragments":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"Event"}],"abstract":[{"type":"text","text":"Events involving a change to a file system object."}],"identifier":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher\/Event","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"Event"}],"url":"\/documentation\/filesystemeventpublisher\/event"},"doc://FileSystemEventPublisher/documentation/FileSystemEventPublisher":{"role":"collection","title":"FileSystemEventPublisher","abstract":[{"type":"text","text":"A publisher that emits events in the file system."}],"identifier":"doc:\/\/FileSystemEventPublisher\/documentation\/FileSystemEventPublisher","kind":"symbol","type":"topic","url":"\/documentation\/filesystemeventpublisher"}}}
Loading

0 comments on commit 9529234

Please sign in to comment.