提交 f1127c90 编写于 作者: B Benjamin Pasero 提交者: GitHub

Mac: file events are not reported when using workspace path with different...

Mac: file events are not reported when using workspace path with different casing (fixes #1426) (#19918)

* Mac: file events are not reported when using workspace path with different casing (fixes #1426)

* fix test on linux

* more fixes
上级 01ae652d
......@@ -369,4 +369,46 @@ export function writeFileAndFlush(path: string, data: string | NodeBuffer, optio
});
});
});
}
/**
* Copied from: https://github.com/Microsoft/vscode-node-debug/blob/master/src/node/pathUtilities.ts#L83
*
* Given an absolute, normalized, and existing file path 'realpath' returns the exact path that the file has on disk.
* On a case insensitive file system, the returned path might differ from the original path by character casing.
* On a case sensitive file system, the returned path will always be identical to the original path.
* In case of errors, null is returned. But you cannot use this function to verify that a path exists.
* realpathSync does not handle '..' or '.' path segments and it does not take the locale into account.
*/
export function realpathSync(path: string): string {
const dir = paths.dirname(path);
if (path === dir) { // end recursion
return path;
}
const name = paths.basename(path).toLowerCase();
try {
const entries = readdirSync(dir);
const found = entries.filter(e => e.toLowerCase() === name); // use a case insensitive search
if (found.length === 1) {
// on a case sensitive filesystem we cannot determine here, whether the file exists or not, hence we need the 'file exists' precondition
const prefix = realpathSync(dir); // recurse
if (prefix) {
return paths.join(prefix, found[0]);
}
} else if (found.length > 1) {
// must be a case sensitive $filesystem
const ix = found.indexOf(name);
if (ix >= 0) { // case sensitive
const prefix = realpathSync(dir); // recurse
if (prefix) {
return paths.join(prefix, found[ix]);
}
}
}
} catch (error) {
// silently ignore error
}
return null;
}
\ No newline at end of file
......@@ -202,4 +202,31 @@ suite('Extfs', () => {
});
});
});
test('realpath', (done) => {
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
const newDir = path.join(parentDir, 'extfs', id);
extfs.mkdirp(newDir, 493, (error) => {
// assume case insensitive file system
if (process.platform === 'win32' || process.platform === 'darwin') {
const upper = newDir.toUpperCase();
const real = extfs.realpathSync(upper);
assert.notEqual(real, upper);
assert.equal(real.toUpperCase(), upper);
assert.equal(real, newDir);
}
// linux, unix, etc. -> assume case sensitive file system
else {
const real = extfs.realpathSync(newDir);
assert.equal(real, newDir);
}
extfs.del(parentDir, os.tmpdir(), () => { }, done);
});
});
});
\ No newline at end of file
......@@ -15,6 +15,8 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { FileChangeType } from 'vs/platform/files/common/files';
import { ThrottledDelayer } from 'vs/base/common/async';
import strings = require('vs/base/common/strings');
import { realpathSync } from 'vs/base/node/extfs';
import { isMacintosh } from 'vs/base/common/platform';
import watcher = require('vs/workbench/services/files/node/watcher/common');
import { IWatcherRequest, IWatcherService } from './watcher';
......@@ -36,10 +38,22 @@ export class ChokidarWatcherService implements IWatcherService {
binaryInterval: 1000
};
const chokidarWatcher = chokidar.watch(request.basePath, watcherOpts);
// Chokidar fails when the basePath does not match case-identical to the path on disk
// so we have to find the real casing of the path and do some path massaging to fix this
// see https://github.com/paulmillr/chokidar/issues/418
const originalBasePath = request.basePath;
const realBasePath = isMacintosh ? (realpathSync(originalBasePath) || originalBasePath) : originalBasePath;
const realBasePathLength = realBasePath.length;
const realBasePathDiffers = (originalBasePath !== realBasePath);
if (realBasePathDiffers) {
console.warn(`Watcher basePath does not match version on disk and was corrected (original: ${originalBasePath}, real: ${realBasePath})`);
}
const chokidarWatcher = chokidar.watch(realBasePath, watcherOpts);
// Detect if for some reason the native watcher library fails to load
if (process.platform === 'darwin' && !chokidarWatcher.options.useFsEvents) {
if (isMacintosh && !chokidarWatcher.options.useFsEvents) {
console.error('Watcher is not using native fsevents library and is falling back to unefficient polling.');
}
......@@ -48,10 +62,15 @@ export class ChokidarWatcherService implements IWatcherService {
return new TPromise<void>((c, e, p) => {
chokidarWatcher.on('all', (type: string, path: string) => {
if (path.indexOf(request.basePath) < 0) {
if (path.indexOf(realBasePath) < 0) {
return; // we really only care about absolute paths here in our basepath context here
}
// Make sure to convert the path back to its original basePath form if the realpath is different
if (realBasePathDiffers) {
path = originalBasePath + path.substr(realBasePathLength);
}
let event: watcher.IRawFileChange = null;
// Change
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册