logic: Follow symbolic links to directoris within source paths

* Follow symbolic links to files and references by default now
* Fixed crash on self-referencing symbolic links

bug id = 205
This commit is contained in:
Eberhard Graether
2016-09-28 15:26:43 +02:00
parent d70079825a
commit 52fb2ae6f6
10 changed files with 124 additions and 104 deletions
-23
View File
@@ -1,23 +0,0 @@
#include "io.h"
#include <iostream>
#include <sstream>
#include <string>
int io::numberIn() {
std::string input;
getline( std::cin, input );
std::stringstream stream( input );
int number;
stream >> number;
return number;
}
void io::numberOut(int num) {
std::cout << num;
}
void io::stringOut(const char* str) {
std::cout << str;
}
+1
View File
@@ -0,0 +1 @@
../src/
+1
View File
@@ -0,0 +1 @@
../Settings
+1
View File
@@ -0,0 +1 @@
../main.cpp
+1
View File
@@ -0,0 +1 @@
self
@@ -0,0 +1,4 @@
void test()
{
}
@@ -0,0 +1,4 @@
class Test
{
};
+68 -50
View File
@@ -1,11 +1,14 @@
#include "utility/file/FileSystem.h"
#include <set>
#include "boost/date_time.hpp"
#include "boost/filesystem.hpp"
std::vector<std::string> FileSystem::getFileNamesFromDirectory(
const std::string& path, const std::vector<std::string>& extensions
){
std::set<std::string> ext(extensions.begin(), extensions.end());
std::vector<std::string> files;
if (boost::filesystem::is_directory(path))
@@ -14,7 +17,18 @@ std::vector<std::string> FileSystem::getFileNamesFromDirectory(
boost::filesystem::recursive_directory_iterator endit;
while (it != endit)
{
if (boost::filesystem::is_regular_file(*it) && hasExtension(it->path().string(), extensions))
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())
{
++it;
continue;
}
}
if (boost::filesystem::is_regular_file(*it) && ext.find(it->path().extension().string()) != ext.end())
{
files.push_back(it->path().generic_string());
}
@@ -24,34 +38,6 @@ std::vector<std::string> FileSystem::getFileNamesFromDirectory(
return files;
}
std::vector<std::string> FileSystem::getFileNamesFromDirectoryUpdatedAfter(
const std::string& path, const std::vector<std::string>& extensions, const std::string& timeString
){
std::vector<std::string> files;
const boost::posix_time::ptime time = boost::posix_time::from_iso_string(timeString);
if (boost::filesystem::is_directory(path))
{
boost::filesystem::recursive_directory_iterator it(path);
boost::filesystem::recursive_directory_iterator endit;
while (it != endit)
{
if (boost::filesystem::is_regular_file(*it) && hasExtension(it->path().string(), extensions))
{
std::time_t t = boost::filesystem::last_write_time(*it);
boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t);
if (lastWriteTime >= time)
{
files.push_back(it->path().generic_string());
}
}
++it;
}
}
return files;
}
FileInfo FileSystem::getFileInfoForPath(FilePath filePath)
{
if (filePath.exists())
@@ -64,39 +50,85 @@ FileInfo FileSystem::getFileInfoForPath(FilePath filePath)
}
std::vector<FileInfo> FileSystem::getFileInfosFromPaths(
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions, bool followSymLinks
){
std::set<std::string> ext(fileExtensions.begin(), fileExtensions.end());
std::set<boost::filesystem::path> symlinkDirs;
std::set<boost::filesystem::path> filePaths;
std::vector<FileInfo> files;
for (const FilePath& path: paths)
{
if (path.isDirectory())
{
boost::filesystem::recursive_directory_iterator it(path.path());
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 (ec)
if (boost::filesystem::is_symlink(*it))
{
it.pop();
continue;
if (!followSymLinks)
{
it.no_push();
continue;
}
// 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);
}
}
if (boost::filesystem::is_regular_file(*it) &&
(!fileExtensions.size() || hasExtension(it->path().string(), fileExtensions)))
(!ext.size() || ext.find(it->path().extension().string()) != ext.end()))
{
boost::filesystem::path p = boost::filesystem::canonical(it->path());
if (filePaths.find(p) != filePaths.end())
{
continue;
}
filePaths.insert(p);
std::time_t t = boost::filesystem::last_write_time(*it);
boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t);
files.push_back(FileInfo(it->path(), lastWriteTime));
}
}
}
else if (path.exists() && (!fileExtensions.size() || path.hasExtension(fileExtensions)))
else if (path.exists() && (!ext.size() || ext.find(path.extension()) != ext.end()))
{
boost::filesystem::path p = boost::filesystem::canonical(path.path());
if (filePaths.find(p) != filePaths.end())
{
continue;
}
filePaths.insert(p);
std::time_t t = boost::filesystem::last_write_time(path.path());
boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t);
files.push_back(FileInfo(path, lastWriteTime));
}
}
return files;
}
@@ -204,20 +236,6 @@ std::string FileSystem::filePathWithoutExtension(const std::string& path)
return boost::filesystem::path(path).replace_extension().generic_string();
}
bool FileSystem::hasExtension(const std::string& filepath, const std::vector<std::string>& extensions)
{
boost::filesystem::path path(filepath);
for (std::string extension : extensions)
{
if (path.extension() == extension)
{
return true;
}
}
return false;
}
bool FileSystem::equivalent(const std::string& pathA, const std::string& pathB)
{
if (exists(pathA) && exists(pathB))
+1 -4
View File
@@ -12,13 +12,11 @@ class FileSystem
public:
static std::vector<std::string> getFileNamesFromDirectory(
const std::string& path, const std::vector<std::string>& extensions);
static std::vector<std::string> getFileNamesFromDirectoryUpdatedAfter(
const std::string& path, const std::vector<std::string>& extensions, const std::string& timeString);
static FileInfo getFileInfoForPath(FilePath filePath);
static std::vector<FileInfo> getFileInfosFromPaths(
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions);
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions, bool followSymLinks = true);
static TimePoint getLastWriteTime(const FilePath& filePath);
static std::string getTimeStringNow();
@@ -38,7 +36,6 @@ public:
static std::string extension(const std::string& path);
static std::string filePathWithoutExtension(const std::string& path);
static bool hasExtension(const std::string& filepath, const std::vector<std::string>& extensions);
static bool equivalent(const std::string& pathA, const std::string& pathB);
};
+43 -27
View File
@@ -18,9 +18,11 @@ public:
std::vector<std::string> cppFiles =
FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions);
TS_ASSERT_EQUALS(cppFiles.size(), 2);
TS_ASSERT_EQUALS(cppFiles.size(), 4);
TS_ASSERT(isInVector(cppFiles, "data/FileSystemTestSuite/main.cpp"));
TS_ASSERT(isInVector(cppFiles, "data/FileSystemTestSuite/Settings/sample.cpp"));
TS_ASSERT(isInVector(cppFiles, "data/FileSystemTestSuite/src/main.cpp"));
TS_ASSERT(isInVector(cppFiles, "data/FileSystemTestSuite/src/test.cpp"));
}
void test_find_h_files()
@@ -31,9 +33,10 @@ public:
std::vector<std::string> headerFiles =
FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions);
TS_ASSERT_EQUALS(headerFiles.size(), 2);
TS_ASSERT_EQUALS(headerFiles.size(), 3);
TS_ASSERT(isInVector(headerFiles, "data/FileSystemTestSuite/tictactoe.h"));
TS_ASSERT(isInVector(headerFiles, "data/FileSystemTestSuite/Settings/player.h"));
TS_ASSERT(isInVector(headerFiles, "data/FileSystemTestSuite/src/test.h"));
}
void test_find_all_source_files()
@@ -46,29 +49,7 @@ public:
std::vector<std::string> sourceFiles =
FileSystem::getFileNamesFromDirectory("data/FileSystemTestSuite", extensions);
TS_ASSERT_EQUALS(sourceFiles.size(), 5);
}
void test_find_updated_source_files()
{
std::string timeString = FileSystem::getTimeStringNow();
std::fstream fileStream;
fileStream.open("./data/FileSystemTestSuite/update.c");
fileStream << "update";
fileStream.close();
std::vector<std::string> extensions;
extensions.push_back(".h");
extensions.push_back(".c");
extensions.push_back(".hpp");
extensions.push_back(".cpp");
std::vector<std::string> sourceFiles =
FileSystem::getFileNamesFromDirectoryUpdatedAfter("data/FileSystemTestSuite", extensions, timeString);
TS_ASSERT_EQUALS(sourceFiles.size(), 1);
TS_ASSERT_EQUALS(sourceFiles[0], "data/FileSystemTestSuite/update.c");
TS_ASSERT_EQUALS(sourceFiles.size(), 8);
}
void test_find_file_infos()
@@ -79,11 +60,33 @@ public:
extensions.push_back(".cpp");
std::vector<FilePath> directoryPaths;
directoryPaths.push_back("./data/FileSystemTestSuite");
directoryPaths.push_back("./data/FileSystemTestSuite/src");
std::vector<FileInfo> files = FileSystem::getFileInfosFromPaths(directoryPaths, extensions);
std::vector<FileInfo> files = FileSystem::getFileInfosFromPaths(directoryPaths, extensions, false);
TS_ASSERT_EQUALS(files.size(), 2);
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/test.cpp"));
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/test.h"));
}
void test_find_file_infos_with_symlinks()
{
std::vector<std::string> extensions;
extensions.push_back(".h");
extensions.push_back(".hpp");
extensions.push_back(".cpp");
std::vector<FilePath> directoryPaths;
directoryPaths.push_back("./data/FileSystemTestSuite/src");
std::vector<FileInfo> files = FileSystem::getFileInfosFromPaths(directoryPaths, extensions, true);
TS_ASSERT_EQUALS(files.size(), 5);
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/Settings/player.h"));
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/Settings/sample.cpp"));
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/main.cpp"));
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/Settings/src/test.cpp"));
TS_ASSERT(isInFileInfos(files, "./data/FileSystemTestSuite/src/Settings/src/test.h"));
}
void test_filesystem_finds_existing_files()
@@ -121,4 +124,17 @@ private:
{
return std::end(files) != std::find(std::begin(files), std::end(files), filename);
}
bool isInFileInfos(const std::vector<FileInfo>& infos, const std::string filename)
{
for (const FileInfo& info : infos)
{
if (info.path.str() == filename)
{
return true;
}
}
return false;
}
};