fix: nsfw can't watch parent folder, just ignore .git in symlink sub wiki folder before any side-effect

This commit is contained in:
lin onetwo 2025-11-24 17:37:01 +08:00
parent 5310365a8a
commit 23aa09eaac

View file

@ -235,40 +235,22 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
this.logger.log('WatchFileSystemAdaptor File system watching is disabled for this workspace'); this.logger.log('WatchFileSystemAdaptor File system watching is disabled for this workspace');
return; return;
} }
// Initialize inverse index from boot.files
this.initializeInverseFilesIndex();
// Setup base excluded paths (permanent exclusions) for main wiki
// wikiFolderLocation is the parent of watchPathBase (tiddlers folder)
const wikiFolderLocation = currentWorkspace && 'wikiFolderLocation' in currentWorkspace
? currentWorkspace.wikiFolderLocation
: path.dirname(this.watchPathBase);
this.baseExcludedPaths = [
path.join(this.watchPathBase, 'subwiki'),
path.join(this.watchPathBase, '$__StoryList'),
// Add pattern-based exclusions at wiki folder level (not tiddlers folder)
// .git is at wiki folder level: wiki/.git, not wiki/tiddlers/.git
...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)),
];
} catch (error) { } catch (error) {
this.logger.alert('WatchFileSystemAdaptor Failed to check enableFileSystemWatch setting:', error); this.logger.alert('WatchFileSystemAdaptor Failed to check enableFileSystemWatch setting:', error);
return; return;
} }
} else {
// Fallback when workspaceID is not available
this.initializeInverseFilesIndex();
// Use parent directory as wikiFolderLocation fallback
const wikiFolderLocation = path.dirname(this.watchPathBase);
this.baseExcludedPaths = [
path.join(this.watchPathBase, 'subwiki'),
path.join(this.watchPathBase, '$__StoryList'),
// Add pattern-based exclusions at wiki folder level
...this.excludedPathPatterns.map(pattern => path.join(wikiFolderLocation, pattern)),
];
} }
// Initialize inverse index from boot.files
this.initializeInverseFilesIndex();
// Setup base excluded paths (permanent exclusions) for main wiki
// Only include paths that are subdirectories of watchPathBase
this.baseExcludedPaths = [
path.join(this.watchPathBase, 'subwiki'),
path.join(this.watchPathBase, '$__StoryList'),
];
// Setup nsfw watcher // Setup nsfw watcher
try { try {
this.watcher = await nsfw( this.watcher = await nsfw(
@ -438,6 +420,23 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
this.pendingDeletions.set(fileAbsolutePath, timer); this.pendingDeletions.set(fileAbsolutePath, timer);
} }
/**
* Check if a path contains any excluded pattern (like .git, node_modules)
* This checks all parts of the path, so it will catch:
* - Direct .git directories: wiki/.git/config
* - Sub-wiki .git directories: wiki/tiddlers/subwiki/.git/index.lock
* - Symlinked .git directories: wiki/tiddlers/link-to-subwiki/.git/config
* @param filePath File or directory path to check
* @returns true if path should be excluded
*/
private shouldExcludeByPattern(filePath: string): boolean {
// Check if any part of the path contains excluded patterns
return this.excludedPathPatterns.some(pattern => {
const pathParts = filePath.split(path.sep);
return pathParts.includes(pattern);
});
}
/** /**
* Handle NSFW file system change events * Handle NSFW file system change events
*/ */
@ -458,6 +457,27 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
// Compute absolute path // Compute absolute path
const fileAbsolutePath = path.join(directory, fileName); const fileAbsolutePath = path.join(directory, fileName);
// Early check: skip files in excluded patterns (e.g., .git, node_modules)
if (this.shouldExcludeByPattern(fileAbsolutePath) || this.shouldExcludeByPattern(directory)) {
this.logger.log(`WatchFileSystemAdaptor Skipping file in excluded pattern directory: ${fileAbsolutePath}`);
continue;
}
// Early check: skip if it's a directory (nsfw sometimes reports directory changes)
// Must check before processing to avoid creating tiddlers for .git files
if (action === nsfw.actions.CREATED || action === nsfw.actions.MODIFIED) {
try {
const stats = fs.statSync(fileAbsolutePath);
if (stats.isDirectory()) {
this.logger.log(`WatchFileSystemAdaptor Skipping directory: ${fileAbsolutePath}`);
continue;
}
} catch {
// File might have been deleted already, skip
continue;
}
}
// Check if this file is in our dynamic exclusion list (for files being saved/deleted by the app) // Check if this file is in our dynamic exclusion list (for files being saved/deleted by the app)
const subWikiForExclusion = this.inverseFilesIndex.getSubWikiForFile(fileAbsolutePath); const subWikiForExclusion = this.inverseFilesIndex.getSubWikiForFile(fileAbsolutePath);
const isExcluded = subWikiForExclusion const isExcluded = subWikiForExclusion
@ -484,18 +504,6 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor {
// Handle different event types // Handle different event types
if (action === nsfw.actions.CREATED || action === nsfw.actions.MODIFIED) { if (action === nsfw.actions.CREATED || action === nsfw.actions.MODIFIED) {
// Skip if it's a directory (nsfw sometimes reports directory changes)
try {
const stats = fs.statSync(fileAbsolutePath);
if (stats.isDirectory()) {
this.logger.log(`WatchFileSystemAdaptor Skipping directory: ${fileAbsolutePath}`);
continue;
}
} catch {
// File might have been deleted already, skip
continue;
}
// Cancel any pending deletion for this file (e.g., git revert scenario) // Cancel any pending deletion for this file (e.g., git revert scenario)
this.cancelPendingDeletion(fileAbsolutePath); this.cancelPendingDeletion(fileAbsolutePath);