Skip to content

Commit 34565c3

Browse files
committed
[Utility] Add a cross-platform filesystem watching utility
This adds a cross-plaform filesystem watching utility based on FSEventStream (macOS) and inotify (Linux). The eventual goal is to add APIs in libSwiftPM so long living clients like IDE can be notified of changes in the manifest or the file structure of the package. The inotify wrapper needs some work but that can happen in follow on commits. <rdar://problem/45795219> Add APIs for watching the filesystem for changes
1 parent ecb157e commit 34565c3

File tree

8 files changed

+722
-0
lines changed

8 files changed

+722
-0
lines changed

Sources/Utility/FSWatch.swift

Lines changed: 609 additions & 0 deletions
Large diffs are not rendered by default.

Sources/clibc/include/clibc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#include <fts.h>
22

3+
#if defined(__linux__)
4+
#include <sys/inotify.h>
5+
#endif
6+
37
#define STR_EXPAND(VALUE) #VALUE
48
#define STR(VALUE) STR_EXPAND(VALUE)
59

Tests/ExtraTests/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj

Tests/ExtraTests/Package.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// swift-tools-version:4.2
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "ExtraTests",
7+
dependencies: [
8+
.package(path: "../../"),
9+
],
10+
targets: [
11+
.testTarget(
12+
name: "ExtraTests",
13+
dependencies: ["Utility"]),
14+
]
15+
)

Tests/ExtraTests/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# ExtraTests
2+
3+
This contains some extra tests that are not suitable for running on the official
4+
CI but can be run elsewhere.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import XCTest
2+
3+
import Basic
4+
import Utility
5+
6+
class FSWatchTests: XCTestCase {
7+
8+
func testBasics() throws {
9+
let tmpDir = try TemporaryDirectory(removeTreeOnDeinit: true)
10+
let path = tmpDir.path
11+
12+
// Construct the paths that we need to watch.
13+
let pathsToWatch = [
14+
path.appending(component: "foo"),
15+
path.appending(component: "bar"),
16+
]
17+
18+
// Create the paths.
19+
for path in pathsToWatch {
20+
try localFileSystem.createDirectory(path)
21+
}
22+
23+
let condition = Condition()
24+
let delegate = Delegate(condition)
25+
26+
let watcher = FSWatch(paths: pathsToWatch, delegate: delegate)
27+
try watcher.start()
28+
29+
for file in ["a", "b", "c"] {
30+
let filePath = path.appending(components: "foo", file)
31+
try localFileSystem.writeFileContents(filePath, bytes: "")
32+
}
33+
34+
condition.whileLocked {
35+
condition.wait()
36+
}
37+
38+
XCTAssertFalse(delegate.receivedEvents.isEmpty)
39+
}
40+
}
41+
42+
class Delegate: FSWatchDelegate {
43+
var receivedEvents: [AbsolutePath] = []
44+
45+
let condition: Condition
46+
47+
init(_ condition: Condition) {
48+
self.condition = condition
49+
}
50+
51+
func pathsDidReceiveEvent(_ paths: [AbsolutePath]) {
52+
receivedEvents += paths
53+
54+
print(paths)
55+
56+
condition.whileLocked {
57+
condition.signal()
58+
}
59+
}
60+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#if !canImport(ObjectiveC)
2+
import XCTest
3+
4+
extension FSWatchTests {
5+
// DO NOT MODIFY: This is autogenerated, use:
6+
// `swift test --generate-linuxmain`
7+
// to regenerate.
8+
static let __allTests__FSWatchTests = [
9+
("testBasics", testBasics),
10+
]
11+
}
12+
13+
public func __allTests() -> [XCTestCaseEntry] {
14+
return [
15+
testCase(FSWatchTests.__allTests__FSWatchTests),
16+
]
17+
}
18+
#endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
3+
import ExtraTests
4+
5+
var tests = [XCTestCaseEntry]()
6+
tests += ExtraTests.__allTests()
7+
8+
XCTMain(tests)

0 commit comments

Comments
 (0)