148 lines
4.7 KiB
C
148 lines
4.7 KiB
C
|
//===-- 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/Support/VirtualFileSystem.h"
|
||
|
#include <mutex>
|
||
|
#include <string>
|
||
|
|
||
|
namespace llvm {
|
||
|
class FileCollectorFileSystem;
|
||
|
class Twine;
|
||
|
|
||
|
class FileCollectorBase {
|
||
|
public:
|
||
|
FileCollectorBase();
|
||
|
virtual ~FileCollectorBase();
|
||
|
|
||
|
void addFile(const Twine &file);
|
||
|
void addDirectory(const Twine &Dir);
|
||
|
|
||
|
protected:
|
||
|
bool markAsSeen(StringRef Path) {
|
||
|
if (Path.empty())
|
||
|
return false;
|
||
|
return Seen.insert(Path).second;
|
||
|
}
|
||
|
|
||
|
virtual void addFileImpl(StringRef SrcPath) = 0;
|
||
|
|
||
|
virtual llvm::vfs::directory_iterator
|
||
|
addDirectoryImpl(const llvm::Twine &Dir,
|
||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS,
|
||
|
std::error_code &EC) = 0;
|
||
|
|
||
|
/// Synchronizes access to internal data structures.
|
||
|
std::mutex Mutex;
|
||
|
|
||
|
/// Tracks already seen files so they can be skipped.
|
||
|
StringSet<> Seen;
|
||
|
};
|
||
|
|
||
|
/// Captures file system interaction and generates data to be later replayed
|
||
|
/// with the RedirectingFileSystem.
|
||
|
///
|
||
|
/// For any file that gets accessed we eventually create:
|
||
|
/// - a copy of the file inside Root
|
||
|
/// - a record in RedirectingFileSystem mapping that maps:
|
||
|
/// current real path -> path to the copy in Root
|
||
|
///
|
||
|
/// That intent is that later when the mapping is used by RedirectingFileSystem
|
||
|
/// it simulates the state of FS that we collected.
|
||
|
///
|
||
|
/// We generate file copies and mapping lazily - see writeMapping and copyFiles.
|
||
|
/// We don't try to capture the state of the file at the exact time when it's
|
||
|
/// accessed. Files might get changed, deleted ... we record only the "final"
|
||
|
/// state.
|
||
|
///
|
||
|
/// In order to preserve the relative topology of files we use their real paths
|
||
|
/// as relative paths inside of the Root.
|
||
|
class FileCollector : public FileCollectorBase {
|
||
|
public:
|
||
|
/// Helper utility that encapsulates the logic for canonicalizing a virtual
|
||
|
/// path and a path to copy from.
|
||
|
class PathCanonicalizer {
|
||
|
public:
|
||
|
struct PathStorage {
|
||
|
SmallString<256> CopyFrom;
|
||
|
SmallString<256> VirtualPath;
|
||
|
};
|
||
|
|
||
|
/// Canonicalize a pair of virtual and real paths.
|
||
|
PathStorage canonicalize(StringRef SrcPath);
|
||
|
|
||
|
private:
|
||
|
/// Replace with a (mostly) real path, or don't modify. Resolves symlinks
|
||
|
/// in the directory, using \a CachedDirs to avoid redundant lookups, but
|
||
|
/// leaves the filename as a possible symlink.
|
||
|
void updateWithRealPath(SmallVectorImpl<char> &Path);
|
||
|
|
||
|
StringMap<std::string> CachedDirs;
|
||
|
};
|
||
|
|
||
|
/// \p Root is the directory where collected files are will be stored.
|
||
|
/// \p OverlayRoot is VFS mapping root.
|
||
|
/// \p Root directory gets created in copyFiles unless it already exists.
|
||
|
FileCollector(std::string Root, std::string OverlayRoot);
|
||
|
|
||
|
/// Write the yaml mapping (for the VFS) to the given file.
|
||
|
std::error_code writeMapping(StringRef MappingFile);
|
||
|
|
||
|
/// Copy the files into the root directory.
|
||
|
///
|
||
|
/// When StopOnError 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 StopOnError = true);
|
||
|
|
||
|
/// Create a VFS that uses \p Collector to collect files accessed via \p
|
||
|
/// BaseFS.
|
||
|
static IntrusiveRefCntPtr<vfs::FileSystem>
|
||
|
createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
|
||
|
std::shared_ptr<FileCollector> Collector);
|
||
|
|
||
|
private:
|
||
|
friend FileCollectorFileSystem;
|
||
|
|
||
|
void addFileToMapping(StringRef VirtualPath, StringRef RealPath) {
|
||
|
if (sys::fs::is_directory(VirtualPath))
|
||
|
VFSWriter.addDirectoryMapping(VirtualPath, RealPath);
|
||
|
else
|
||
|
VFSWriter.addFileMapping(VirtualPath, RealPath);
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
void addFileImpl(StringRef SrcPath) override;
|
||
|
|
||
|
llvm::vfs::directory_iterator
|
||
|
addDirectoryImpl(const llvm::Twine &Dir,
|
||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS,
|
||
|
std::error_code &EC) override;
|
||
|
|
||
|
/// The directory where collected files are copied to in copyFiles().
|
||
|
const std::string Root;
|
||
|
|
||
|
/// The root directory where the VFS overlay lives.
|
||
|
const std::string OverlayRoot;
|
||
|
|
||
|
/// The yaml mapping writer.
|
||
|
vfs::YAMLVFSWriter VFSWriter;
|
||
|
|
||
|
/// Helper utility for canonicalizing paths.
|
||
|
PathCanonicalizer Canonicalizer;
|
||
|
};
|
||
|
|
||
|
} // end namespace llvm
|
||
|
|
||
|
#endif // LLVM_SUPPORT_FILE_COLLECTOR_H
|