WIP work on rewatching child directories

This commit is contained in:
Ash Wilson
2017-06-23 09:33:47 -04:00
parent 60e6da9097
commit a5f217fd51
2 changed files with 82 additions and 15 deletions

View File

@@ -212,8 +212,66 @@ describe('NativeWatcherRegistry', function () {
expect(stoppedNode).toBe(true)
})
it("keeps a parent watcher that's still running")
it('reassigns new child watchers when a parent watcher is stopped', async function () {
const CHILD0 = new MockNative('child0')
const CHILD1 = new MockNative('child1')
const PARENT = new MockNative('parent')
it('reassigns new child watchers when a parent watcher is stopped')
const parentDir = path.join('parent')
const childDir0 = path.join(parentDir, 'child0')
const childDir1 = path.join(parentDir, 'child1')
createNative = dir => {
if (dir === parentDir) {
return PARENT
} else if (dir === childDir0) {
return CHILD0
} else if (dir === childDir1) {
return CHILD1
} else {
throw new Error(`Unexpected directory ${dir}`)
}
}
const parentWatcher = new MockWatcher(parentDir)
const childWatcher0 = new MockWatcher(childDir0)
const childWatcher1 = new MockWatcher(childDir1)
await registry.attach(parentWatcher)
await Promise.all([
registry.attach(childWatcher0),
registry.attach(childWatcher1)
])
// All three watchers should share the parent watcher's native watcher.
expect(parentWatcher.native).toBe(PARENT)
expect(childWatcher0.native).toBe(PARENT)
expect(childWatcher1.native).toBe(PARENT)
// Stopping the parent should detach and recreate the child watchers.
// (Here, they'll be the same watcher instances used before, because of the fake createNative implementation.)
PARENT.stop()
expect(childWatcher0.native).toBe(CHILD0)
expect(childWatcher1.native).toBe(CHILD1)
expect(registry.tree.lookup(['parent']).when({
parent: () => false,
missing: () => false,
children: () => true
})).toBe(true)
expect(registry.tree.lookup(['parent', 'child0']).when({
parent: () => true,
missing: () => false,
children: () => false
})).toBe(true)
expect(registry.tree.lookup(['parent', 'child1']).when({
parent: () => true,
missing: () => false,
children: () => false
})).toBe(true)
})
})
})

View File

@@ -21,7 +21,7 @@ class RegistryNode {
// exist.
lookup (pathSegments) {
if (pathSegments.length === 0) {
return new ChildrenResult(this.leaves())
return new ChildrenResult(this.leaves([]))
}
const child = this.children[pathSegments[0]]
@@ -85,13 +85,17 @@ class RegistryNode {
return Object.keys(this.children).length === 0 ? null : this
}
// Private: Discover all {RegistryWatcherNode} instances beneath this tree node.
// Private: Discover all {RegistryWatcherNode} instances beneath this tree node and the child paths
// that they are watching.
//
// Returns: A possibly empty {Array} of {RegistryWatcherNode} instances that are the descendants of this node.
leaves () {
// * `prefix` {Array} of intermediate path segments to prepend to the resulting child paths.
//
// Returns: A possibly empty {Array} of `{node, path}` objects describing {RegistryWatcherNode}
// instances beneath this node.
leaves (prefix) {
const results = []
for (const p of Object.keys(this.children)) {
results.push(...this.children[p].leaves())
results.push(...this.children[p].leaves(prefix + [p]))
}
return results
}
@@ -104,8 +108,11 @@ class RegistryWatcherNode {
// Private: Allocate a new node to track a {NativeWatcher}.
//
// * `nativeWatcher` An existing {NativeWatcher} instance.
constructor (nativeWatcher) {
// * `childPaths` {Array} of child directories that are currently the responsibility of this
// {NativeWatcher}, if any
constructor (nativeWatcher, childPaths) {
this.nativeWatcher = nativeWatcher
this.childPaths = new Set(childPaths)
}
// Private: Accessor for the {NativeWatcher}.
@@ -133,9 +140,11 @@ class RegistryWatcherNode {
// Private: Discover this {RegistryWatcherNode} instance.
//
// Returns: An {Array} containing this node.
leaves () {
return [this]
// * `prefix` {Array} of intermediate path segments to prepend to the resulting child paths.
//
// Returns: An {Array} containing a `{node, path}` object describing this node.
leaves (prefix) {
return [{node: this, path: prefix}]
}
}
@@ -243,9 +252,9 @@ export default class NativeWatcherRegistry {
const normalizedDirectory = await watcher.getNormalizedPathPromise()
const pathSegments = normalizedDirectory.split(path.sep).filter(segment => segment.length > 0)
const attachToNew = () => {
const attachToNew = (childPaths) => {
const native = this.createNative(normalizedDirectory)
const leaf = new RegistryWatcherNode(native)
const leaf = new RegistryWatcherNode(native, childPaths)
this.tree = this.tree.insert(pathSegments, leaf)
const sub = native.onWillStop(() => {
@@ -268,7 +277,7 @@ export default class NativeWatcherRegistry {
watcher.attachToNative(native, subpath)
},
children: children => {
const newNative = attachToNew()
const newNative = attachToNew([])
// One or more NativeWatchers exist on child directories of the requested path.
for (let i = 0; i < children.length; i++) {
@@ -281,7 +290,7 @@ export default class NativeWatcherRegistry {
childNative.stop()
}
},
missing: attachToNew
missing: () => attachToNew([])
})
}
}