@@ -22,6 +22,7 @@ import {
2222
2323import { FileChangeType , FileSystemWatcherClient , IFileSystemWatcherServer , INsfw , WatchOptions } from '../../common' ;
2424import { FileChangeCollection } from '../file-change-collection' ;
25+ import { shouldIgnorePath } from '../shared' ;
2526
2627export interface WatcherOptions {
2728 excludesPattern : ParsedPattern [ ] ;
@@ -45,7 +46,7 @@ export interface NsfwFileSystemWatcherOption {
4546}
4647
4748@Injectable ( { multiple : true } )
48- export class FileSystemWatcherServer implements IFileSystemWatcherServer {
49+ export class FileSystemWatcherServer extends Disposable implements IFileSystemWatcherServer {
4950 private static readonly PARCEL_WATCHER_BACKEND = isWindows ? 'windows' : isLinux ? 'inotify' : 'fs-events' ;
5051
5152 private WATCHER_HANDLERS = new Map <
@@ -57,8 +58,6 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
5758
5859 protected client : FileSystemWatcherClient | undefined ;
5960
60- protected readonly toDispose = new DisposableCollection ( Disposable . create ( ( ) => this . setClient ( undefined ) ) ) ;
61-
6261 protected changes = new FileChangeCollection ( ) ;
6362
6463 @Autowired ( ILogServiceManager )
@@ -67,12 +66,14 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
6766 private logger : ILogService ;
6867
6968 constructor ( @Optional ( ) private readonly excludes : string [ ] = [ ] ) {
69+ super ( ) ;
7070 this . logger = this . loggerManager . getLogger ( SupportLogNamespace . Node ) ;
71- }
7271
73- dispose ( ) : void {
74- this . toDispose . dispose ( ) ;
75- this . WATCHER_HANDLERS . clear ( ) ;
72+ this . addDispose (
73+ Disposable . create ( ( ) => {
74+ this . WATCHER_HANDLERS . clear ( ) ;
75+ } ) ,
76+ ) ;
7677 }
7778
7879 /**
@@ -150,7 +151,7 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
150151 } ) ;
151152 toDisposeWatcher . push ( Disposable . create ( ( ) => this . WATCHER_HANDLERS . delete ( watcherId as number ) ) ) ;
152153 toDisposeWatcher . push ( await this . start ( watcherId , watchPath , options ) ) ;
153- this . toDispose . push ( toDisposeWatcher ) ;
154+ this . addDispose ( toDisposeWatcher ) ;
154155 return watcherId ;
155156 }
156157
@@ -180,24 +181,10 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
180181 * @param events
181182 */
182183 protected trimChangeEvent ( events : ParcelWatcher . Event [ ] ) : ParcelWatcher . Event [ ] {
183- events = events . filter ( ( event : ParcelWatcher . Event ) => {
184- if ( event . path ) {
185- if ( this . isTempFile ( event . path ) ) {
186- // write-file-atomic 源文件xxx.xx 对应的临时文件为 xxx.xx.22243434
187- // 这类文件的更新应当完全隐藏掉
188- return false ;
189- }
190- }
191- return true ;
192- } ) ;
193-
184+ events = events . filter ( ( event : ParcelWatcher . Event ) => ! shouldIgnorePath ( event . path ) ) ;
194185 return events ;
195186 }
196187
197- private isTempFile ( path : string ) {
198- return / \. \d { 7 } \d + $ / . test ( path ) ;
199- }
200-
201188 private getDefaultWatchExclude ( ) {
202189 return [ '**/.git/objects/**' , '**/.git/subtree-cache/**' , '**/node_modules/**/*' , '**/.hg/store/**' ] ;
203190 }
@@ -251,20 +238,14 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
251238 return undefined ; // watch 失败则返回 undefined
252239 } ;
253240
254- /**
255- * 由于 parcel/watcher 在 Linux 下存在内存越界访问问题触发了 sigsegv 导致 crash,所以在 Linux 下仍旧使用 nsfw
256- * 社区相关 issue: https://github.com/parcel-bundler/watcher/issues/49
257- * 后续这里的 watcher 模块需要重构掉,先暂时这样处理
258- *
259- * 代码来自 issue: https://github.com/opensumi/core/pull/1437/files?diff=split&w=0#diff-9de963117a88a70d7c58974bf2b092c61a196d6eef719846d78ca5c9d100b796 的旧代码处理
260- */
261241 if ( this . isEnableNSFW ( ) ) {
262242 const nsfw = await this . withNSFWModule ( ) ;
263243 const watcher : INsfw . NSFW = await nsfw (
264244 realPath ,
265245 ( events : INsfw . ChangeEvent [ ] ) => this . handleNSFWEvents ( events , watcherId ) ,
266246 {
267- errorCallback : ( error : any ) => {
247+ errorCallback : ( err ) => {
248+ this . logger . error ( 'NSFW watcher encountered an error and will stop watching.' , err ) ;
268249 // see https://github.com/atom/github/issues/342
269250 this . unwatchFileChanges ( watcherId ) ;
270251 } ,
@@ -314,15 +295,15 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
314295 }
315296
316297 setClient ( client : FileSystemWatcherClient | undefined ) {
317- if ( client && this . toDispose . disposed ) {
298+ if ( client && this . disposed ) {
318299 return ;
319300 }
320301 this . client = client ;
321302 }
322303
323304 /**
324- * @deprecated
325- * 主要是用来跳过 jest 测试
305+ * 由于 parcel/watcher 在 Linux 下存在内存越界访问问题触发了 sigsegv 导致 crash,所以在 Linux 下仍旧使用 nsfw
306+ * 社区相关 issue: https://github.com/parcel-bundler/watcher/issues/49
326307 */
327308 private isEnableNSFW ( ) : boolean {
328309 return isLinux ;
@@ -347,9 +328,9 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
347328 return true ;
348329 }
349330
350- return ! this . isTempFile ( event . file ! ) ;
331+ return ! shouldIgnorePath ( event . file ) ;
351332 } ) ;
352- // 合并下事件,由于 resolvePath 耗时较久,这里只用当前事件路径及文件名去重,后续处理事件再获取真实路径
333+
353334 const mergedEvents = uniqBy ( filterEvents , ( event ) => {
354335 if ( event . action === INsfw . actions . RENAMED ) {
355336 const deletedPath = paths . join ( event . directory , event . oldFile ! ) ;
@@ -360,47 +341,58 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
360341 return event . action + paths . join ( event . directory , event . file ! ) ;
361342 } ) ;
362343
363- for ( const event of mergedEvents ) {
364- if ( event . action === INsfw . actions . RENAMED ) {
365- const deletedPath = this . resolvePath ( event . directory , event . oldFile ! ) ;
366- if ( isIgnored ( watcherId , deletedPath ) ) {
367- continue ;
368- }
344+ await Promise . all (
345+ mergedEvents . map ( async ( event ) => {
346+ switch ( event . action ) {
347+ case INsfw . actions . RENAMED :
348+ {
349+ const deletedPath = await this . resolvePath ( event . directory , event . oldFile ! ) ;
350+ if ( isIgnored ( watcherId , deletedPath ) ) {
351+ return ;
352+ }
369353
370- this . pushDeleted ( deletedPath ) ;
354+ this . pushDeleted ( deletedPath ) ;
371355
372- if ( event . newDirectory ) {
373- const path = this . resolvePath ( event . newDirectory , event . newFile ! ) ;
374- if ( isIgnored ( watcherId , path ) ) {
375- continue ;
376- }
356+ if ( event . newDirectory ) {
357+ const path = await this . resolvePath ( event . newDirectory , event . newFile ! ) ;
358+ if ( isIgnored ( watcherId , path ) ) {
359+ return ;
360+ }
377361
378- this . pushAdded ( path ) ;
379- } else {
380- const path = this . resolvePath ( event . directory , event . newFile ! ) ;
381- if ( isIgnored ( watcherId , path ) ) {
382- continue ;
383- }
362+ this . pushAdded ( path ) ;
363+ } else {
364+ const path = await this . resolvePath ( event . directory , event . newFile ! ) ;
365+ if ( isIgnored ( watcherId , path ) ) {
366+ return ;
367+ }
384368
385- this . pushAdded ( path ) ;
386- }
387- } else {
388- const path = this . resolvePath ( event . directory , event . file ! ) ;
389- if ( isIgnored ( watcherId , path ) ) {
390- continue ;
391- }
369+ this . pushAdded ( path ) ;
370+ }
371+ }
372+ break ;
373+ default :
374+ {
375+ const path = await this . resolvePath ( event . directory , event . file ! ) ;
376+ if ( isIgnored ( watcherId , path ) ) {
377+ return ;
378+ }
392379
393- if ( event . action === INsfw . actions . CREATED ) {
394- this . pushAdded ( path ) ;
395- }
396- if ( event . action === INsfw . actions . DELETED ) {
397- this . pushDeleted ( path ) ;
398- }
399- if ( event . action === INsfw . actions . MODIFIED ) {
400- this . pushUpdated ( path ) ;
380+ switch ( event . action ) {
381+ case INsfw . actions . CREATED :
382+ this . pushAdded ( path ) ;
383+ break ;
384+ case INsfw . actions . DELETED :
385+ this . pushDeleted ( path ) ;
386+ break ;
387+ case INsfw . actions . MODIFIED :
388+ this . pushUpdated ( path ) ;
389+ break ;
390+ }
391+ }
392+ break ;
401393 }
402- }
403- }
394+ } ) ,
395+ ) ;
404396 }
405397
406398 private async withNSFWModule ( ) : Promise < typeof import ( 'nsfw' ) > {
@@ -426,16 +418,16 @@ export class FileSystemWatcherServer implements IFileSystemWatcherServer {
426418 this . fireDidFilesChanged ( ) ;
427419 }
428420
429- protected resolvePath ( directory : string , file : string ) : string {
421+ protected async resolvePath ( directory : string , file : string ) : Promise < string > {
430422 const path = paths . join ( directory , file ) ;
431423 // 如果是 linux 则获取一下真实 path,以防返回的是软连路径被过滤
432424 if ( isLinux ) {
433425 try {
434- return fs . realpathSync . native ( path ) ;
426+ return await fs . realpath . native ( path ) ;
435427 } catch ( _e ) {
436428 try {
437429 // file does not exist try to resolve directory
438- return paths . join ( fs . realpathSync . native ( directory ) , file ) ;
430+ return paths . join ( await fs . realpath . native ( directory ) , file ) ;
439431 } catch ( _e ) {
440432 // directory does not exist fall back to symlink
441433 return path ;
0 commit comments