diff --git a/src/lib/project/SourceGroup.cpp b/src/lib/project/SourceGroup.cpp index ebaffa13..4d7427cb 100644 --- a/src/lib/project/SourceGroup.cpp +++ b/src/lib/project/SourceGroup.cpp @@ -3,6 +3,7 @@ #include "settings/SourceGroupSettings.h" #include "utility/file/FileManager.h" #include "utility/file/FilePath.h" +#include "utility/file/FileSystem.h" SourceGroup::~SourceGroup() { @@ -28,8 +29,8 @@ void SourceGroup::fetchAllSourceFilePaths() m_sourceFilePathsToIndex.clear(); FileManager fileManager; fileManager.update( - getAllSourcePaths(), - getSourceGroupSettings()->getExcludePathsExpandedAndAbsolute(), + getAllSourcePaths(), + getSourceGroupSettings()->getExcludePathsExpandedAndAbsolute(), getSourceGroupSettings()->getSourceExtensions() ); m_allSourceFilePaths = fileManager.getAllSourceFilePaths(); @@ -46,6 +47,16 @@ void SourceGroup::fetchSourceFilePathsToIndex(const std::set& staticSo } } +std::set SourceGroup::getIndexedPaths() +{ + return findAndAddSymlinkedDirectories(getSourceGroupSettings()->getSourcePathsExpandedAndAbsolute()); +} + +std::set SourceGroup::getExcludedPaths() +{ + return findAndAddSymlinkedDirectories(getSourceGroupSettings()->getExcludePathsExpandedAndAbsolute()); +} + std::set SourceGroup::getAllSourceFilePaths() const { return m_allSourceFilePaths; @@ -55,3 +66,20 @@ std::set SourceGroup::getSourceFilePathsToIndex() const { return m_sourceFilePathsToIndex; } + +std::set SourceGroup::findAndAddSymlinkedDirectories(const std::vector& paths) +{ + std::set resultPaths; + for (const FilePath& path: paths) + { + if (path.exists()) + { + resultPaths.insert(path); + } + } + + std::set symLinkPaths = FileSystem::getSymLinkedDirectories(paths); + resultPaths.insert(symLinkPaths.begin(), symLinkPaths.end()); + + return resultPaths; +} diff --git a/src/lib/project/SourceGroup.h b/src/lib/project/SourceGroup.h index 396d1fd7..70b52070 100644 --- a/src/lib/project/SourceGroup.h +++ b/src/lib/project/SourceGroup.h @@ -33,12 +33,17 @@ public: std::set* filesToIndex, bool fullRefresh) = 0; protected: + std::set getIndexedPaths(); + std::set getExcludedPaths(); + std::set m_allSourceFilePaths; std::set m_sourceFilePathsToIndex; private: virtual std::shared_ptr getSourceGroupSettings() = 0; virtual std::vector getAllSourcePaths() const = 0; + + std::set findAndAddSymlinkedDirectories(const std::vector& paths); }; #endif // SOURCE_GROUP_H diff --git a/src/lib/utility/file/FileSystem.cpp b/src/lib/utility/file/FileSystem.cpp index 9f36e01f..9a156cf5 100644 --- a/src/lib/utility/file/FileSystem.cpp +++ b/src/lib/utility/file/FileSystem.cpp @@ -138,6 +138,55 @@ std::vector FileSystem::getFileInfosFromPaths( return files; } +std::set FileSystem::getSymLinkedDirectories(const std::vector& paths) +{ + std::set symlinkDirs; + std::set filePaths; + + for (const FilePath& path: paths) + { + if (path.isDirectory()) + { + boost::filesystem::recursive_directory_iterator it(path.path(), boost::filesystem::symlink_option::recurse); + boost::filesystem::recursive_directory_iterator endit; + boost::system::error_code ec; + for ( ; it != endit ; it.increment(ec) ) + { + if (boost::filesystem::is_symlink(*it)) + { + // check for self-referencing symlinks + boost::filesystem::path p = boost::filesystem::read_symlink(*it); + if (p.filename() == p.string() && p.filename() == it->path().filename()) + { + continue; + } + + // check for duplicates when following directory symlinks + if (boost::filesystem::is_directory(*it)) + { + boost::filesystem::path absDir = boost::filesystem::canonical(p, it->path().parent_path()); + + if (symlinkDirs.find(absDir) != symlinkDirs.end()) + { + it.no_push(); + continue; + } + + symlinkDirs.insert(absDir); + } + } + } + } + } + + std::set files; + for (auto& p : symlinkDirs) + { + files.insert(FilePath(p)); + } + return files; +} + unsigned long long FileSystem::getFileByteSize(const FilePath& filePath) { return boost::filesystem::file_size(filePath.path()); diff --git a/src/lib/utility/file/FileSystem.h b/src/lib/utility/file/FileSystem.h index 84e0b434..1bb611ce 100644 --- a/src/lib/utility/file/FileSystem.h +++ b/src/lib/utility/file/FileSystem.h @@ -1,6 +1,7 @@ #ifndef FILE_SYSTEM_H #define FILE_SYSTEM_H +#include #include #include @@ -18,6 +19,8 @@ public: static std::vector getFileInfosFromPaths( const std::vector& paths, const std::vector& fileExtensions, bool followSymLinks = true); + static std::set getSymLinkedDirectories(const std::vector& paths); + static unsigned long long getFileByteSize(const FilePath& filePath); static TimeStamp getLastWriteTime(const FilePath& filePath); diff --git a/src/lib_cxx/project/SourceGroupCxxCdb.cpp b/src/lib_cxx/project/SourceGroupCxxCdb.cpp index 854ee57b..d48501a1 100644 --- a/src/lib_cxx/project/SourceGroupCxxCdb.cpp +++ b/src/lib_cxx/project/SourceGroupCxxCdb.cpp @@ -72,23 +72,8 @@ std::vector> SourceGroupCxxCdb::getIndexerComman std::vector compilerFlags; utility::append(compilerFlags, m_settings->getCompilerFlags()); - std::set indexedPaths; - for (const FilePath& p : m_settings->getSourcePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - indexedPaths.insert(p); - } - } - - std::set excludedPaths; - for (const FilePath& p: m_settings->getExcludePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - excludedPaths.insert(p); - } - } + std::set indexedPaths = getIndexedPaths(); + std::set excludedPaths = getExcludedPaths(); const std::set& sourceFilePathsToIndex = (fullRefresh ? getAllSourceFilePaths() : getSourceFilePathsToIndex()); diff --git a/src/lib_cxx/project/SourceGroupCxxEmpty.cpp b/src/lib_cxx/project/SourceGroupCxxEmpty.cpp index 8109e61f..be435c69 100644 --- a/src/lib_cxx/project/SourceGroupCxxEmpty.cpp +++ b/src/lib_cxx/project/SourceGroupCxxEmpty.cpp @@ -51,23 +51,8 @@ std::vector> SourceGroupCxxEmpty::getIndexerComm utility::append(compilerFlags, m_settings->getCompilerFlags()); - std::set indexedPaths; - for (const FilePath& p : m_settings->getSourcePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - indexedPaths.insert(p); - } - } - - std::set excludedPaths; - for (const FilePath& p: m_settings->getExcludePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - excludedPaths.insert(p); - } - } + std::set indexedPaths = getIndexedPaths(); + std::set excludedPaths = getExcludedPaths(); const std::set& sourceFilePathsToIndex = (fullRefresh ? getAllSourceFilePaths() : getSourceFilePathsToIndex()); diff --git a/src/lib_java/project/SourceGroupJava.cpp b/src/lib_java/project/SourceGroupJava.cpp index 9d975f52..c765472f 100644 --- a/src/lib_java/project/SourceGroupJava.cpp +++ b/src/lib_java/project/SourceGroupJava.cpp @@ -36,24 +36,8 @@ std::vector> SourceGroupJava::getIndexerCommands const std::string languageStandard = getSourceGroupSettingsJava()->getStandard(); std::vector classPath = getClassPath(); - - std::set indexedPaths; - for (const FilePath& p: getSourceGroupSettings()->getSourcePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - indexedPaths.insert(p); - } - } - - std::set excludedPaths; - for (const FilePath& p: getSourceGroupSettings()->getExcludePathsExpandedAndAbsolute()) - { - if (p.exists()) - { - excludedPaths.insert(p); - } - } + std::set indexedPaths = getIndexedPaths(); + std::set excludedPaths = getExcludedPaths(); const std::set& sourceFilePathsToIndex = (fullRefresh ? getAllSourceFilePaths() : getSourceFilePathsToIndex()); diff --git a/src/test/FileSystemTestSuite.h b/src/test/FileSystemTestSuite.h index fde275b2..5a9446ae 100644 --- a/src/test/FileSystemTestSuite.h +++ b/src/test/FileSystemTestSuite.h @@ -109,6 +109,18 @@ public: #endif } + void test_find_symlinked_directories() + { +#ifndef _WIN32 + std::vector directoryPaths; + directoryPaths.push_back(FilePath("./data/FileSystemTestSuite/src")); + + std::set dirs = FileSystem::getSymLinkedDirectories(directoryPaths); + + TS_ASSERT_EQUALS(dirs.size(), 2); +#endif + } + void test_filesystem_finds_existing_files() { TS_ASSERT(FileSystem::exists(FilePath("data/FileSystemTestSuite"))); @@ -145,6 +157,11 @@ private: return std::end(files) != std::find(std::begin(files), std::end(files), filename); } + bool isInFiles(const std::set& files, const FilePath& filename) + { + return std::end(files) != files.find(filename); + } + bool isInFileInfos(const std::vector& infos, const std::string filename) { for (const FileInfo& info : infos)