Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests and fixes for ignoring files and directories #3

Merged
merged 3 commits into from
Mar 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/DirTree.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
#include <istream>
#include "Event.hh"

#ifdef _WIN32
#define DIR_SEP "\\"
#else
#define DIR_SEP "/"
#endif

struct DirEntry {
std::string path;
uint64_t mtime;
Expand Down Expand Up @@ -93,7 +99,7 @@ struct DirTree {

// Remove all sub-entries if this is a directory
if (found && found->isDir) {
std::string pathStart = path + "/";
std::string pathStart = path + DIR_SEP;
for (auto it = entries.begin(); it != entries.end();) {
if (it->first.rfind(pathStart, 0) == 0) {
it = entries.erase(it);
Expand Down
11 changes: 11 additions & 0 deletions src/Watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,14 @@ void Watcher::unref() {
void Watcher::onClose(uv_handle_t *handle) {
delete (uv_async_t *)handle;
}

bool Watcher::isIgnored(std::string path) {
for (auto it = mIgnore.begin(); it != mIgnore.end(); it++) {
auto dir = *it + DIR_SEP;
if (*it == path || path.compare(0, dir.size(), dir) == 0) {
return true;
}
}

return false;
}
1 change: 1 addition & 0 deletions src/Watcher.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct Watcher {
bool watch(Function callback);
bool unwatch(Function callback);
void unref();
bool isIgnored(std::string path);

static std::shared_ptr<Watcher> getShared(std::string dir, std::unordered_set<std::string> ignore);

Expand Down
5 changes: 5 additions & 0 deletions src/macos/FSEvents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ void FSEventsCallback(
break;
}

// FSEvents exclusion paths only apply to sub-paths, not the path itself.
if (watcher->mIgnore.count(paths[i]) > 0) {
continue;
}

// Handle unambiguous events first
if (isCreated && !(isRemoved || isModified || isRenamed)) {
watcher->mTree->add(paths[i], 0, isDir);
Expand Down
30 changes: 28 additions & 2 deletions src/watchman/watchman.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ void handleFiles(Watcher &watcher, BSER::Object obj) {
auto mode = file.find("mode")->second.intValue();
auto isNew = file.find("new")->second.boolValue();
auto exists = file.find("exists")->second.boolValue();
auto path = watcher.mDir + "/" + name;
auto path = watcher.mDir + DIR_SEP + name;
if (watcher.isIgnored(path)) {
continue;
}

if (isNew && exists) {
watcher.mEvents.create(path);
} else if (exists && !S_ISDIR(mode)) {
Expand Down Expand Up @@ -271,8 +275,30 @@ void WatchmanBackend::subscribe(Watcher &watcher) {
BSER::Object opts;
opts.emplace("fields", fields);
opts.emplace("since", clock(watcher));
cmd.push_back(opts);

if (watcher.mIgnore.size() > 0) {
BSER::Array ignore;
BSER::Array anyOf;
anyOf.push_back("anyof");

for (auto it = watcher.mIgnore.begin(); it != watcher.mIgnore.end(); it++) {
std::string pathStart = watcher.mDir + DIR_SEP;
if (it->rfind(pathStart, 0) == 0) {
auto relative = it->substr(pathStart.size());
BSER::Array dirname;
dirname.push_back("dirname");
dirname.push_back(relative);
anyOf.push_back(dirname);
}
}

ignore.push_back("not");
ignore.push_back(anyOf);

opts.emplace("expression", ignore);
}

cmd.push_back(opts);
watchmanRequest(cmd);
}

Expand Down
9 changes: 8 additions & 1 deletion src/windows/WindowsBackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ DirTree *BruteForceBackend::readTree(Watcher &watcher) {
do {
if (strcmp(ffd.cFileName, ".") != 0 && strcmp(ffd.cFileName, "..") != 0) {
std::string fullPath = path + "\\" + ffd.cFileName;
if (watcher.mIgnore.count(fullPath) > 0) {
continue;
}

tree->add(fullPath, CONVERT_TIME(ffd.ftLastWriteTime), ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && watcher.mIgnore.count(fullPath) == 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(fullPath);
}
}
Expand Down Expand Up @@ -176,6 +180,9 @@ class Subscription {

void processEvent(PFILE_NOTIFY_INFORMATION info) {
std::string path = mWatcher->mDir + "\\" + utf16ToUtf8(info->FileName, info->FileNameLength / sizeof(WCHAR));
if (mWatcher->isIgnored(path)) {
return;
}

switch (info->Action) {
case FILE_ACTION_ADDED:
Expand Down
43 changes: 43 additions & 0 deletions test/since.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,49 @@ describe('since', () => {
]);
});
});

describe('ignore', () => {
it('should ignore a directory', async () => {
let f1 = getFilename();
let dir = getFilename();
let f2 = getFilename(path.basename(dir));
let ignore = [dir];
await fs.mkdir(dir);
await sleep();
await fschanges.writeSnapshot(tmpDir, snapshotPath, {backend, ignore});
if (isSecondPrecision) {
await sleep(1000);
}

await fs.writeFile(f1, 'hello');
await fs.writeFile(f2, 'sup');
await sleep();

let res = await fschanges.getEventsSince(tmpDir, snapshotPath, {backend, ignore});
assert.deepEqual(res, [
{type: 'create', path: f1}
]);
});

it('should ignore a file', async () => {
let f1 = getFilename();
let f2 = getFilename();
let ignore = [f2];
await fschanges.writeSnapshot(tmpDir, snapshotPath, {backend, ignore});
if (isSecondPrecision) {
await sleep(1000);
}

await fs.writeFile(f1, 'hello');
await fs.writeFile(f2, 'sup');
await sleep();

let res = await fschanges.getEventsSince(tmpDir, snapshotPath, {backend, ignore});
assert.deepEqual(res, [
{type: 'create', path: f1}
]);
});
});
});
});
});
35 changes: 33 additions & 2 deletions test/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,19 @@ describe('watcher', () => {

let c = 0;
const getFilename = (...dir) => path.join(tmpDir, ...dir, `test${c++}${Math.random().toString(31).slice(2)}`);
let ignoreDir, ignoreFile;

before(async () => {
tmpDir = path.join(fs.realpathSync(require('os').tmpdir()), Math.random().toString(31).slice(2));
fs.mkdirpSync(tmpDir);
ignoreDir = getFilename();
ignoreFile = getFilename();
await new Promise(resolve => setTimeout(resolve, 100));
fschanges.subscribe(tmpDir, fn, {backend});
fschanges.subscribe(tmpDir, fn, {backend, ignore: [ignoreDir, ignoreFile]});
});

after(async () => {
fschanges.unsubscribe(tmpDir, fn, {backend});
fschanges.unsubscribe(tmpDir, fn, {backend, ignore: [ignoreDir, ignoreFile]});
});

describe('files', () => {
Expand Down Expand Up @@ -403,6 +406,34 @@ describe('watcher', () => {
]);
});
});

describe('ignore', () => {
it('should ignore a directory', async () => {
let f1 = getFilename();
let f2 = getFilename(path.basename(ignoreDir));
await fs.mkdir(ignoreDir);

fs.writeFile(f1, 'hello');
fs.writeFile(f2, 'sup');

let res = await nextEvent();
assert.deepEqual(res, [
{type: 'create', path: f1}
]);
});

it('should ignore a file', async () => {
let f1 = getFilename();

fs.writeFile(f1, 'hello');
fs.writeFile(ignoreFile, 'sup');

let res = await nextEvent();
assert.deepEqual(res, [
{type: 'create', path: f1}
]);
});
});
});
});
});