Skip to content

Commit

Permalink
add filtering support for os x
Browse files Browse the repository at this point in the history
  • Loading branch information
jjallaire committed Aug 22, 2011
1 parent e1f3819 commit ae5633a
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 111 deletions.
59 changes: 38 additions & 21 deletions src/cpp/core/system/PosixFileScanner.cpp
Expand Up @@ -40,13 +40,15 @@ int entryFilter(const struct dirent *entry)

Error scanFiles(const FileInfo& fromRoot,
bool recursive,
const boost::function<bool(const FileInfo&)>& filter,
tree<FileInfo>* pTree)
{
return scanFiles(pTree->set_head(fromRoot), recursive, pTree);
return scanFiles(pTree->set_head(fromRoot), recursive, filter, pTree);
}

Error scanFiles(const tree<FileInfo>::iterator_base& fromNode,
bool recursive,
const boost::function<bool(const FileInfo&)>& filter,
tree<FileInfo>* pTree)
{
// clear all existing
Expand Down Expand Up @@ -92,31 +94,46 @@ Error scanFiles(const tree<FileInfo>::iterator_base& fromNode,
continue;
}

// add the correct type of FileEntry
if ( S_ISDIR(st.st_mode))
// create the FileInfo
FileInfo fileInfo;
if (S_ISDIR(st.st_mode))
{
tree<FileInfo>::iterator_base child =
pTree->append_child(fromNode, FileInfo(path, true));
if (recursive)
fileInfo = FileInfo(path, true);
}
else
{
fileInfo = FileInfo(path,
false,
st.st_size,
#ifdef __APPLE__
st.st_mtimespec.tv_sec);
#else
st.st_mtime);
#endif
}

// apply the filter (if any)
if (!filter || filter(fileInfo))
{
// add the correct type of FileEntry
if (fileInfo.isDirectory())
{
Error error = scanFiles(child, true, pTree);
if (error)
tree<FileInfo>::iterator_base child = pTree->append_child(fromNode,
fileInfo);
if (recursive)
{
LOG_ERROR(error);
continue;
Error error = scanFiles(child, true, filter, pTree);
if (error)
{
LOG_ERROR(error);
continue;
}
}
}
}
else
{
pTree->append_child(fromNode, FileInfo(path,
false,
st.st_size,
#ifdef __APPLE__
st.st_mtimespec.tv_sec));
#else
st.st_mtime));
#endif
else
{
pTree->append_child(fromNode, fileInfo);
}
}
}

Expand Down
152 changes: 75 additions & 77 deletions src/cpp/core/system/file_monitor/FileMonitor.cpp
Expand Up @@ -60,7 +60,7 @@ bool notDirectories(const FileInfo& fileInfo,
{
std::string path = fileInfo.absolutePath();

for (int i=0; i<dirNames.size(); i++)
for (std::size_t i=0; i<dirNames.size(); i++)
{
if (fileInfo.isDirectory() && boost::algorithm::ends_with(path,
dirNames[i]))
Expand All @@ -74,6 +74,7 @@ bool notDirectories(const FileInfo& fileInfo,

std::string prefixString(const std::string& str, char ch)
{
std::string prefixed;
prefixed.reserve(str.length() + 1);
prefixed.append(1, ch);
prefixed.append(str);
Expand Down Expand Up @@ -237,93 +238,90 @@ Error discoverAndProcessFileChanges(
tree<FileInfo>* pTree,
const Callbacks::FilesChanged& onFilesChanged)
{
// find this path in our fileTree
tree<FileInfo>::iterator it = std::find(pTree->begin(),
pTree->end(),
fileInfo);

// if we don't find it then it may have been excluded by a filter, just bail
if (it == pTree->end())
return Success();

// scan this directory into a new tree which we can compare to the old tree
tree<FileInfo> subdirTree;
Error error = scanFiles(fileInfo, recursive, filter, &subdirTree);
if (error)
return error;

// find this path in our fileTree
tree<FileInfo>::iterator it = std::find(pTree->begin(),
pTree->end(),
fileInfo);
if (it != pTree->end())
// handle recursive vs. non-recursive scan differnetly
if (recursive)
{
// handle recursive vs. non-recursive scan differnetly
if (recursive)
{
// check for changes on full subtree
std::vector<FileChangeEvent> fileChanges;
tree<FileInfo> existingSubtree(it);
collectFileChangeEvents(existingSubtree.begin(),
existingSubtree.end(),
subdirTree.begin(),
subdirTree.end(),
&fileChanges);

// fire events
onFilesChanged(fileChanges);

// wholesale replace subtree
pTree->insert_subtree_after(it, subdirTree.begin());
pTree->erase(it);
}
else
// check for changes on full subtree
std::vector<FileChangeEvent> fileChanges;
tree<FileInfo> existingSubtree(it);
collectFileChangeEvents(existingSubtree.begin(),
existingSubtree.end(),
subdirTree.begin(),
subdirTree.end(),
&fileChanges);

// fire events
onFilesChanged(fileChanges);

// wholesale replace subtree
pTree->insert_subtree_after(it, subdirTree.begin());
pTree->erase(it);
}
else
{
// scan for changes on just the children
std::vector<FileChangeEvent> childrenFileChanges;
collectFileChangeEvents(pTree->begin(it),
pTree->end(it),
subdirTree.begin(subdirTree.begin()),
subdirTree.end(subdirTree.begin()),
&childrenFileChanges);

// build up actual file changes and mutate the tree as appropriate
std::vector<FileChangeEvent> fileChanges;
BOOST_FOREACH(const FileChangeEvent& fileChange, childrenFileChanges)
{
// scan for changes on just the children
std::vector<FileChangeEvent> childrenFileChanges;
collectFileChangeEvents(pTree->begin(it),
pTree->end(it),
subdirTree.begin(subdirTree.begin()),
subdirTree.end(subdirTree.begin()),
&childrenFileChanges);

// build up actual file changes and mutate the tree as appropriate
std::vector<FileChangeEvent> fileChanges;
BOOST_FOREACH(const FileChangeEvent& fileChange, childrenFileChanges)
switch(fileChange.type())
{
case FileChangeEvent::FileAdded:
{
switch(fileChange.type())
{
case FileChangeEvent::FileAdded:
{
Error error = processFileAdded(it,
fileChange,
recursive,
filter,
pTree,
&fileChanges);
if (error)
LOG_ERROR(error);
break;
}
case FileChangeEvent::FileModified:
{
processFileModified(it, fileChange, pTree, &fileChanges);
break;
}
case FileChangeEvent::FileRemoved:
{
processFileRemoved(it,
fileChange,
recursive,
pTree,
&fileChanges);
break;
}
case FileChangeEvent::None:
default:
break;
}
Error error = processFileAdded(it,
fileChange,
recursive,
filter,
pTree,
&fileChanges);
if (error)
LOG_ERROR(error);
break;
}
case FileChangeEvent::FileModified:
{
processFileModified(it, fileChange, pTree, &fileChanges);
break;
}
case FileChangeEvent::FileRemoved:
{
processFileRemoved(it,
fileChange,
recursive,
pTree,
&fileChanges);
break;
}
case FileChangeEvent::None:
default:
break;
}

// fire events
onFilesChanged(fileChanges);
}
}
else
{
LOG_WARNING_MESSAGE("Unable to find treeItem for " +
fileInfo.absolutePath());

// fire events
onFilesChanged(fileChanges);
}

return Success();
Expand Down
37 changes: 24 additions & 13 deletions src/cpp/core/system/file_monitor/MacFileMonitor.cpp
Expand Up @@ -43,6 +43,7 @@ class FileEventContext : boost::noncopyable
FSEventStreamRef streamRef;
FilePath rootPath;
bool recursive;
boost::function<bool(const FileInfo&)> filter;
tree<FileInfo> fileTree;
Callbacks::FilesChanged onFilesChanged;
Callbacks::ReportError onMonitoringError;
Expand Down Expand Up @@ -89,17 +90,23 @@ void fileEventCallback(ConstFSEventStreamRef streamRef,
// get FileInfo for this directory
FileInfo fileInfo(path, true);

// check for need to do recursive scan
bool recursive = pContext->recursive &&
(eventFlags[i] & kFSEventStreamEventFlagMustScanSubDirs);

// process changes
Error error = impl::discoverAndProcessFileChanges(fileInfo,
recursive,
&(pContext->fileTree),
pContext->onFilesChanged);
if (error)
LOG_ERROR(error);
// apply the filter (if any)
if (!pContext->filter || pContext->filter(fileInfo))
{
// check for need to do recursive scan
bool recursive = pContext->recursive &&
(eventFlags[i] & kFSEventStreamEventFlagMustScanSubDirs);

// process changes
Error error = impl::discoverAndProcessFileChanges(
fileInfo,
recursive,
pContext->filter,
&(pContext->fileTree),
pContext->onFilesChanged);
if (error)
LOG_ERROR(error);
}
}
}

Expand Down Expand Up @@ -143,10 +150,10 @@ namespace detail {
// register a new file monitor
Handle registerMonitor(const FilePath& filePath,
bool recursive,
const boost::function<bool(const FileInfo&)>& filter,
const Callbacks& callbacks)
{
// allocate file path
std::string path = filePath.absolutePath();
CFStringRef filePathRef = ::CFStringCreateWithCString(
kCFAllocatorDefault,
filePath.absolutePath().c_str(),
Expand Down Expand Up @@ -180,6 +187,7 @@ Handle registerMonitor(const FilePath& filePath,
FileEventContext* pContext = new FileEventContext();
pContext->rootPath = filePath;
pContext->recursive = recursive;
pContext->filter = filter;
std::auto_ptr<FileEventContext> autoPtrContext(pContext);
FSEventStreamContext context;
context.version = 0;
Expand Down Expand Up @@ -224,7 +232,10 @@ Handle registerMonitor(const FilePath& filePath,
}

// scan the files
Error error = scanFiles(FileInfo(filePath), true, &pContext->fileTree);
Error error = scanFiles(FileInfo(filePath),
recursive,
filter,
&pContext->fileTree);
if (error)
{
// stop, invalidate, release
Expand Down

0 comments on commit ae5633a

Please sign in to comment.