Skip to content

Commit

Permalink
[Support] move FileCollector from LLDB to llvm/Support
Browse files Browse the repository at this point in the history
The file collector class is useful for creating reproducers,
not just for LLDB, but for other tools as well in LLVM/Clang.

Differential Revision: https://reviews.llvm.org/D65237

llvm-svn: 366956
  • Loading branch information
hyp committed Jul 24, 2019
1 parent 017e272 commit 86814bf
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 80 deletions.
62 changes: 13 additions & 49 deletions lldb/include/lldb/Utility/FileCollector.h
Expand Up @@ -11,65 +11,29 @@

#include "lldb/Utility/FileSpec.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/VirtualFileSystem.h"

#include <mutex>
#include "llvm/Support/FileCollector.h"

namespace lldb_private {

/// Collects files into a directory and generates a mapping that can be used by
/// the VFS.
class FileCollector {
class FileCollector : public llvm::FileCollector {
public:
FileCollector(const FileSpec &root, const FileSpec &overlay);

void AddFile(const llvm::Twine &file);
void AddFile(const FileSpec &file) { return AddFile(file.GetPath()); }

/// Write the yaml mapping (for the VFS) to the given file.
std::error_code WriteMapping(const FileSpec &mapping_file);

/// Copy the files into the root directory.
///
/// When stop_on_error is true (the default) we abort as soon as one file
/// cannot be copied. This is relatively common, for example when a file was
/// removed after it was added to the mapping.
std::error_code CopyFiles(bool stop_on_error = true);

protected:
void AddFileImpl(llvm::StringRef src_path);

bool MarkAsSeen(llvm::StringRef path) { return m_seen.insert(path).second; }
FileCollector(const FileSpec &root, const FileSpec &overlay) :
llvm::FileCollector(root.GetPath(), overlay.GetPath()) {}

bool GetRealPath(llvm::StringRef src_path,
llvm::SmallVectorImpl<char> &result);
using llvm::FileCollector::AddFile;

void AddFileToMapping(llvm::StringRef virtual_path,
llvm::StringRef real_path) {
m_vfs_writer.addFileMapping(virtual_path, real_path);
void AddFile(const FileSpec &file) {
std::string path = file.GetPath();
llvm::FileCollector::AddFile(path);
}

/// Synchronizes adding files.
std::mutex m_mutex;

/// The root directory where files are copied.
FileSpec m_root;

/// The root directory where the VFS overlay lives.
FileSpec m_overlay_root;

/// Tracks already seen files so they can be skipped.
llvm::StringSet<> m_seen;

/// The yaml mapping writer.
llvm::vfs::YAMLVFSWriter m_vfs_writer;

/// Caches real_path calls when resolving symlinks.
llvm::StringMap<std::string> m_symlink_map;
/// Write the yaml mapping (for the VFS) to the given file.
std::error_code WriteMapping(const FileSpec &mapping_file) {
std::string path = mapping_file.GetPath();
return llvm::FileCollector::WriteMapping(path);
}
};

} // namespace lldb_private
Expand Down
1 change: 0 additions & 1 deletion lldb/source/Utility/CMakeLists.txt
Expand Up @@ -23,7 +23,6 @@ add_lldb_library(lldbUtility
DataEncoder.cpp
DataExtractor.cpp
Environment.cpp
FileCollector.cpp
Event.cpp
FileSpec.cpp
IOObject.cpp
Expand Down
1 change: 0 additions & 1 deletion lldb/unittests/Utility/CMakeLists.txt
Expand Up @@ -10,7 +10,6 @@ add_lldb_unittest(UtilityTests
DataExtractorTest.cpp
EnvironmentTest.cpp
EventTest.cpp
FileCollectorTest.cpp
FileSpecTest.cpp
FlagsTest.cpp
JSONTest.cpp
Expand Down
74 changes: 74 additions & 0 deletions llvm/include/llvm/Support/FileCollector.h
@@ -0,0 +1,74 @@
//===-- FileCollector.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_FILE_COLLECTOR_H
#define LLVM_SUPPORT_FILE_COLLECTOR_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/VirtualFileSystem.h"

#include <mutex>

namespace llvm {

/// Collects files into a directory and generates a mapping that can be used by
/// the VFS.
class FileCollector {
public:
FileCollector(std::string root, std::string overlay);

void AddFile(const Twine &file);

/// Write the yaml mapping (for the VFS) to the given file.
std::error_code WriteMapping(StringRef mapping_file);

/// Copy the files into the root directory.
///
/// When stop_on_error is true (the default) we abort as soon as one file
/// cannot be copied. This is relatively common, for example when a file was
/// removed after it was added to the mapping.
std::error_code CopyFiles(bool stop_on_error = true);

private:
void AddFileImpl(StringRef src_path);

bool MarkAsSeen(StringRef path) { return m_seen.insert(path).second; }

bool GetRealPath(StringRef src_path,
SmallVectorImpl<char> &result);

void AddFileToMapping(StringRef virtual_path,
StringRef real_path) {
m_vfs_writer.addFileMapping(virtual_path, real_path);
}

/// Synchronizes adding files.
std::mutex m_mutex;

/// The root directory where files are copied.
std::string m_root;

/// The root directory where the VFS overlay lives.
std::string m_overlay_root;

/// Tracks already seen files so they can be skipped.
StringSet<> m_seen;

/// The yaml mapping writer.
vfs::YAMLVFSWriter m_vfs_writer;

/// Caches real_path calls when resolving symlinks.
StringMap<std::string> m_symlink_map;
};

} // end namespace llvm

#endif // LLVM_SUPPORT_FILE_COLLECTOR_H
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Expand Up @@ -89,6 +89,7 @@ add_llvm_library(LLVMSupport
Error.cpp
ErrorHandling.cpp
FileCheck.cpp
FileCollector.cpp
FileUtilities.cpp
FileOutputBuffer.cpp
FoldingSet.cpp
Expand Down
Expand Up @@ -6,14 +6,12 @@
//
//===----------------------------------------------------------------------===//

#include "lldb/Utility/FileCollector.h"

#include "llvm/Support/FileCollector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"

using namespace lldb_private;
using namespace llvm;

static bool IsCaseSensitivePath(StringRef path) {
Expand All @@ -34,9 +32,9 @@ static bool IsCaseSensitivePath(StringRef path) {
return true;
}

FileCollector::FileCollector(const FileSpec &root, const FileSpec &overlay_root)
: m_root(root), m_overlay_root(overlay_root) {
sys::fs::create_directories(m_root.GetPath(), true);
FileCollector::FileCollector(std::string root, std::string overlay_root)
: m_root(std::move(root)), m_overlay_root(std::move(overlay_root)) {
sys::fs::create_directories(this->m_root, true);
}

bool FileCollector::GetRealPath(StringRef src_path,
Expand Down Expand Up @@ -71,8 +69,6 @@ void FileCollector::AddFile(const Twine &file) {
}

void FileCollector::AddFileImpl(StringRef src_path) {
std::string root = m_root.GetPath();

// We need an absolute src path to append to the root.
SmallString<256> absolute_src = src_path;
sys::fs::make_absolute(absolute_src);
Expand All @@ -94,7 +90,7 @@ void FileCollector::AddFileImpl(StringRef src_path) {
if (!GetRealPath(absolute_src, copy_from))
copy_from = virtual_path;

SmallString<256> dst_path = StringRef(root);
SmallString<256> dst_path = StringRef(m_root);
sys::path::append(dst_path, sys::path::relative_path(copy_from));

// Always map a canonical src path to its real path into the YAML, by doing
Expand Down Expand Up @@ -162,17 +158,16 @@ std::error_code FileCollector::CopyFiles(bool stop_on_error) {
return {};
}

std::error_code FileCollector::WriteMapping(const FileSpec &mapping_file) {
std::error_code FileCollector::WriteMapping(StringRef mapping_file) {
std::lock_guard<std::mutex> lock(m_mutex);

std::string root = m_overlay_root.GetPath();

StringRef root = m_overlay_root;
m_vfs_writer.setOverlayDir(root);
m_vfs_writer.setCaseSensitivity(IsCaseSensitivePath(root));
m_vfs_writer.setUseExternalNames(false);

std::error_code ec;
raw_fd_ostream os(mapping_file.GetPath(), ec, sys::fs::F_Text);
raw_fd_ostream os(mapping_file, ec, sys::fs::F_Text);
if (ec)
return ec;

Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/Support/CMakeLists.txt
Expand Up @@ -30,6 +30,7 @@ add_llvm_unittest(SupportTests
ErrorOrTest.cpp
ErrorTest.cpp
FileCheckTest.cpp
FileCollectorTest.cpp
FileOutputBufferTest.cpp
FormatVariadicTest.cpp
GlobPatternTest.cpp
Expand Down
Expand Up @@ -9,13 +9,10 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "lldb/Utility/FileCollector.h"
#include "lldb/Utility/FileSpec.h"

#include "llvm/Support/FileCollector.h"
#include "llvm/Support/FileSystem.h"

using namespace llvm;
using namespace lldb_private;

namespace llvm {
namespace vfs {
Expand All @@ -35,8 +32,8 @@ class TestingFileCollector : public FileCollector {
using FileCollector::m_symlink_map;
using FileCollector::m_vfs_writer;

bool HasSeen(FileSpec fs) {
return m_seen.find(fs.GetPath()) != m_seen.end();
bool HasSeen(StringRef fs) {
return m_seen.find(fs) != m_seen.end();
}
};

Expand Down Expand Up @@ -104,23 +101,23 @@ struct ScopedFile {

TEST(FileCollectorTest, AddFile) {
ScopedDir root("add_file_root", true);
FileSpec root_fs(root.Path);
std::string root_fs = root.Path.str();
TestingFileCollector file_collector(root_fs, root_fs);

file_collector.AddFile(FileSpec("/path/to/a"));
file_collector.AddFile(FileSpec("/path/to/b"));
file_collector.AddFile(FileSpec("/path/to/c"));
file_collector.AddFile("/path/to/a");
file_collector.AddFile("/path/to/b");
file_collector.AddFile("/path/to/c");

// Make sure the root is correct.
EXPECT_EQ(file_collector.m_root, root_fs);

// Make sure we've seen all the added files.
EXPECT_TRUE(file_collector.HasSeen(FileSpec("/path/to/a")));
EXPECT_TRUE(file_collector.HasSeen(FileSpec("/path/to/b")));
EXPECT_TRUE(file_collector.HasSeen(FileSpec("/path/to/c")));
EXPECT_TRUE(file_collector.HasSeen("/path/to/a"));
EXPECT_TRUE(file_collector.HasSeen("/path/to/b"));
EXPECT_TRUE(file_collector.HasSeen("/path/to/c"));

// Make sure we've only seen the added files.
EXPECT_FALSE(file_collector.HasSeen(FileSpec("/path/to/d")));
EXPECT_FALSE(file_collector.HasSeen("/path/to/d"));
}

TEST(FileCollectorTest, CopyFiles) {
Expand All @@ -131,7 +128,7 @@ TEST(FileCollectorTest, CopyFiles) {

// Create file collector and add files.
ScopedDir root("copy_files_root", true);
FileSpec root_fs(root.Path);
std::string root_fs = root.Path.str();
TestingFileCollector file_collector(root_fs, root_fs);
file_collector.AddFile(a.Path);
file_collector.AddFile(b.Path);
Expand Down Expand Up @@ -173,7 +170,7 @@ TEST(FileCollectorTest, Symlinks) {

// Root where files are copied to.
ScopedDir reproducer_root("reproducer_root", true);
FileSpec root_fs(reproducer_root.Path);
std::string root_fs = reproducer_root.Path.str();
TestingFileCollector file_collector(root_fs, root_fs);

// Add all the files to the collector.
Expand Down

0 comments on commit 86814bf

Please sign in to comment.