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:
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../src/
|
||||
@@ -0,0 +1 @@
|
||||
../Settings
|
||||
@@ -0,0 +1 @@
|
||||
../main.cpp
|
||||
@@ -0,0 +1 @@
|
||||
self
|
||||
@@ -0,0 +1,4 @@
|
||||
void test()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Test
|
||||
{
|
||||
|
||||
};
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user