Skip to content

Commit

Permalink
wip: restructure watcher backend events
Browse files Browse the repository at this point in the history
Differential Revision: D67289194
  • Loading branch information
robhogan authored and facebook-github-bot committed Dec 16, 2024
1 parent 3dc52c4 commit 9e0bcbd
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 129 deletions.
47 changes: 16 additions & 31 deletions packages/metro-file-map/src/Watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
*/

import type {
ChangeEventMetadata,
Console,
CrawlerOptions,
FileData,
Path,
PerfLogger,
WatcherBackendChangeEvent,
WatchmanClocks,
} from './flow-types';
import type {WatcherOptions as WatcherBackendOptions} from './watchers/common';
Expand Down Expand Up @@ -163,14 +163,7 @@ export class Watcher extends EventEmitter {
}
}

async watch(
onChange: (
type: string,
filePath: string,
root: string,
metadata: ChangeEventMetadata,
) => void,
) {
async watch(onChange: (change: WatcherBackendChangeEvent) => void) {
const {extensions, ignorePattern, useWatchman} = this._options;

// WatchmanWatcher > FSEventsWatcher > sane.NodeWatcher
Expand Down Expand Up @@ -214,29 +207,21 @@ export class Watcher extends EventEmitter {

watcher.once('ready', () => {
clearTimeout(rejectTimeout);
watcher.on(
'all',
(
type: string,
filePath: string,
root: string,
metadata: ChangeEventMetadata,
) => {
const basename = path.basename(filePath);
if (basename.startsWith(this._options.healthCheckFilePrefix)) {
if (type === ADD_EVENT || type === CHANGE_EVENT) {
debug(
'Observed possible health check cookie: %s in %s',
filePath,
root,
);
this._handleHealthCheckObservation(basename);
}
return;
watcher.on('all', (change: WatcherBackendChangeEvent) => {
const basename = path.basename(change.relativePath);
if (basename.startsWith(this._options.healthCheckFilePrefix)) {
if (change.event === ADD_EVENT || change.event === CHANGE_EVENT) {
debug(
'Observed possible health check cookie: %s in %s',
change.relativePath,
root,
);
this._handleHealthCheckObservation(basename);
}
onChange(type, filePath, root, metadata);
},
);
return;
}
onChange(change);
});
resolve(watcher);
});
});
Expand Down
14 changes: 14 additions & 0 deletions packages/metro-file-map/src/flow-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,20 @@ export type RawMockMap = Map<string, Path>;

export type ReadOnlyRawMockMap = $ReadOnlyMap<string, Path>;

export type WatcherBackendChangeEvent =
| $ReadOnly<{
event: 'change' | 'add',
relativePath: string,
root: string,
metadata: ChangeEventMetadata,
}>
| $ReadOnly<{
event: 'delete',
relativePath: string,
root: string,
metadata?: void,
}>;

export type WatchmanClockSpec =
| string
| $ReadOnly<{scm: $ReadOnly<{'mergebase-with': string}>}>;
Expand Down
59 changes: 28 additions & 31 deletions packages/metro-file-map/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type {
PerfLoggerFactory,
WatchmanClocks,
WorkerMetadata,
WatcherBackendChangeEvent,
} from './flow-types';
import type {IJestWorker} from 'jest-worker';

Expand Down Expand Up @@ -862,27 +863,23 @@ export default class FileMap extends EventEmitter {
nextEmit = null;
};

const onChange = (
type: string,
filePath: Path,
root: Path,
metadata: ?ChangeEventMetadata,
) => {
const onChange = (change: WatcherBackendChangeEvent) => {
if (
metadata &&
change.metadata &&
// Ignore all directory events
(metadata.type === 'd' ||
(change.metadata.type === 'd' ||
// Ignore regular files with unwatched extensions
(metadata.type === 'f' && !hasWatchedExtension(filePath)) ||
(change.metadata.type === 'f' &&
!hasWatchedExtension(change.relativePath)) ||
// Don't emit events relating to symlinks if enableSymlinks: false
(!this._options.enableSymlinks && metadata?.type === 'l'))
(!this._options.enableSymlinks && change.metadata?.type === 'l'))
) {
return;
}

const absoluteFilePath = path.join(
root,
normalizePathSeparatorsToSystem(filePath),
change.root,
normalizePathSeparatorsToSystem(change.relativePath),
);

// Ignore files (including symlinks) whose path matches ignorePattern
Expand All @@ -899,11 +896,10 @@ export default class FileMap extends EventEmitter {
// null, then it is assumed that the watcher does not have capabilities
// to detect modified time, and change processing proceeds.
if (
type === 'change' &&
change.event === 'change' &&
linkStats != null &&
metadata &&
metadata.modifiedTime != null &&
linkStats.modifiedTime === metadata.modifiedTime
change.metadata.modifiedTime != null &&
linkStats.modifiedTime === change.metadata.modifiedTime
) {
return;
}
Expand All @@ -917,14 +913,15 @@ export default class FileMap extends EventEmitter {
nextEmit != null &&
nextEmit.eventsQueue.find(
event =>
event.type === type &&
event.type === change.event &&
event.filePath === absoluteFilePath &&
((!event.metadata && !metadata) ||
((!event.metadata && !change.metadata) ||
(event.metadata &&
metadata &&
change.metadata &&
event.metadata.modifiedTime != null &&
metadata.modifiedTime != null &&
event.metadata.modifiedTime === metadata.modifiedTime)),
change.metadata.modifiedTime != null &&
event.metadata.modifiedTime ===
change.metadata.modifiedTime)),
)
) {
return null;
Expand All @@ -936,7 +933,7 @@ export default class FileMap extends EventEmitter {
const event = {
filePath: absoluteFilePath,
metadata,
type,
type: change.event,
};
if (nextEmit == null) {
nextEmit = {
Expand All @@ -963,19 +960,19 @@ export default class FileMap extends EventEmitter {

// If the file was added or changed,
// parse it and update the haste map.
if (type === 'add' || type === 'change') {
if (change.event === 'add' || change.event === 'change') {
invariant(
metadata != null && metadata.size != null,
'since the file exists or changed, it should have metadata',
change.metadata.size != null,
'since the file exists or changed, it should have known size',
);
const fileMetadata: FileMetaData = [
'',
metadata.modifiedTime,
metadata.size,
change.metadata.modifiedTime,
change.metadata.size,
0,
'',
null,
metadata.type === 'l' ? 1 : 0,
change.metadata.type === 'l' ? 1 : 0,
];

try {
Expand All @@ -987,7 +984,7 @@ export default class FileMap extends EventEmitter {
{forceInBand: true}, // No need to clean up workers
);
fileSystem.addOrModify(relativeFilePath, fileMetadata);
enqueueEvent(metadata);
enqueueEvent(change.metadata);
} catch (e) {
if (!['ENOENT', 'EACCESS'].includes(e.code)) {
throw e;
Expand All @@ -999,7 +996,7 @@ export default class FileMap extends EventEmitter {
// event for it, and we'll clean up in the usual way at that
// point.
}
} else if (type === 'delete') {
} else if (change.event === 'delete') {
if (linkStats == null) {
// Don't emit deletion events for files we weren't retaining.
// This is expected for deletion of an ignored file.
Expand All @@ -1012,7 +1009,7 @@ export default class FileMap extends EventEmitter {
});
} else {
throw new Error(
`metro-file-map: Unrecognized event type from watcher: ${type}`,
`metro-file-map: Unrecognized event type from watcher: ${change.event}`,
);
}
return null;
Expand Down
54 changes: 20 additions & 34 deletions packages/metro-file-map/src/watchers/NodeWatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

'use strict';

import type {ChangeEventMetadata} from '../flow-types';
import type {
ChangeEventMetadata,
WatcherBackendChangeEvent,
} from '../flow-types';
import type {WatcherOptions} from './common';
import type {FSWatcher, Stats} from 'fs';

Expand Down Expand Up @@ -324,11 +327,16 @@ module.exports = class NodeWatcher extends EventEmitter {
},
(symlink, stats) => {
if (this._register(symlink, 'l')) {
this._rawEmitEvent(ADD_EVENT, path.relative(this.root, symlink), {
modifiedTime: stats.mtime.getTime(),
size: stats.size,
type: 'l',
});
this.emit(ALL_EVENT, {
event: ADD_EVENT,
relativePath: path.relative(this.root, symlink),
root: this.root,
metadata: {
modifiedTime: stats.mtime.getTime(),
size: stats.size,
type: 'l',
},
} as WatcherBackendChangeEvent);
}
},
function endCallback() {},
Expand Down Expand Up @@ -374,21 +382,8 @@ module.exports = class NodeWatcher extends EventEmitter {
*
* See also note above for DEBOUNCE_MS.
*/
_emitEvent({
event,
relativePath,
metadata,
}:
| {
event: 'change' | 'add',
relativePath: string,
metadata: ChangeEventMetadata,
}
| {
event: 'delete',
relativePath: string,
metadata?: void,
}) {
_emitEvent(change: Omit<WatcherBackendChangeEvent, 'root'>) {
const {event, relativePath} = change;
const key = event + '-' + relativePath;
const addKey = ADD_EVENT + '-' + relativePath;
if (event === CHANGE_EVENT && this._changeTimers.has(addKey)) {
Expand All @@ -404,23 +399,14 @@ module.exports = class NodeWatcher extends EventEmitter {
key,
setTimeout(() => {
this._changeTimers.delete(key);
this._rawEmitEvent(event, relativePath, metadata);
this.emit(ALL_EVENT, {
...change,
root: this.root,
} as WatcherBackendChangeEvent);
}, DEBOUNCE_MS),
);
}

/**
* Actually emit the events
*/
_rawEmitEvent(
eventType: string,
file: string,
metadata: ?ChangeEventMetadata,
) {
this.emit(eventType, file, this.root, metadata);
this.emit(ALL_EVENT, eventType, file, this.root, metadata);
}

getPauseReason(): ?string {
return null;
}
Expand Down
27 changes: 9 additions & 18 deletions packages/metro-file-map/src/watchers/WatchmanWatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
* @oncall react_native
*/

import type {ChangeEventMetadata} from '../flow-types';
import type {
ChangeEventMetadata,

Check failure on line 13 in packages/metro-file-map/src/watchers/WatchmanWatcher.js

View workflow job for this annotation

GitHub Actions / Type check, lint, smoke test

'ChangeEventMetadata' is defined but never used. Allowed unused vars must match /^_/u
WatcherBackendChangeEvent,
} from '../flow-types';
import type {WatcherOptions} from './common';
import type {
Client,
Expand Down Expand Up @@ -306,23 +309,11 @@ export default class WatchmanWatcher extends EventEmitter {
/**
* Dispatches the event.
*/
_emitEvent({
event,
relativePath,
metadata,
}:
| {
event: 'change' | 'add',
relativePath: string,
metadata: ChangeEventMetadata,
}
| {
event: 'delete',
relativePath: string,
metadata?: void,
}) {
this.emit(event, relativePath, this.root, metadata);
this.emit(ALL_EVENT, event, relativePath, this.root, metadata);
_emitEvent(change: Omit<WatcherBackendChangeEvent, 'root'>) {
this.emit(ALL_EVENT, {
...change,
root: this.root,
} as WatcherBackendChangeEvent);
}

/**
Expand Down
Loading

0 comments on commit 9e0bcbd

Please sign in to comment.