[llvm] 4125524 - [VFS] Add print/dump to the whole FileSystem hierarchy
Ben Barham via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 17 13:03:13 PDT 2022
Author: Ben Barham
Date: 2022-03-17T13:02:40-07:00
New Revision: 4125524112e00c61547e83804279ef7889c8636a
URL: https://github.com/llvm/llvm-project/commit/4125524112e00c61547e83804279ef7889c8636a
DIFF: https://github.com/llvm/llvm-project/commit/4125524112e00c61547e83804279ef7889c8636a.diff
LOG: [VFS] Add print/dump to the whole FileSystem hierarchy
For now most are implemented by printing out the name of the filesystem,
but this can be expanded in the future. Only `OverlayFileSystem` and
`RedirectingFileSystem` are properly implemented in this patch.
- `OverlayFileSystem`: Prints each filesystem in the order that any
operations are actually run on them. Optionally prints recursively.
- `RedirectingFileSystem`: Prints out all mappings, as well as the
`ExternalFS`. Most of this was already implemented other than the
handling for the `DirectoryRemap` case and to actually print out the
mapping.
Each FS should implement `printImpl` rather than `print`, where the
latter just fowards to the former. This is to avoid spreading the
default arguments through to the subclasses (where we may miss updating
in the future).
Differential Revision: https://reviews.llvm.org/D121421
Added:
Modified:
llvm/include/llvm/Support/VirtualFileSystem.h
llvm/lib/Support/VirtualFileSystem.cpp
llvm/unittests/Support/VirtualFileSystemTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h
index 64b4d4dcd35af..7e93a2146286d 100644
--- a/llvm/include/llvm/Support/VirtualFileSystem.h
+++ b/llvm/include/llvm/Support/VirtualFileSystem.h
@@ -306,6 +306,28 @@ class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> {
/// \returns success if \a path has been made absolute, otherwise a
/// platform-specific error_code.
virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
+
+ enum class PrintType { Summary, Contents, RecursiveContents };
+ void print(raw_ostream &OS, PrintType Type = PrintType::Contents,
+ unsigned IndentLevel = 0) const {
+ printImpl(OS, Type, IndentLevel);
+ }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+
+protected:
+ virtual void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "FileSystem\n";
+ }
+
+ void printIndent(raw_ostream &OS, unsigned IndentLevel) const {
+ for (unsigned i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
};
/// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
@@ -357,6 +379,8 @@ class OverlayFileSystem : public FileSystem {
using const_iterator = FileSystemList::const_reverse_iterator;
using reverse_iterator = FileSystemList::iterator;
using const_reverse_iterator = FileSystemList::const_iterator;
+ using range = iterator_range<iterator>;
+ using const_range = iterator_range<const_iterator>;
/// Get an iterator pointing to the most recently added file system.
iterator overlays_begin() { return FSList.rbegin(); }
@@ -373,6 +397,13 @@ class OverlayFileSystem : public FileSystem {
/// Get an iterator pointing one-past the most recently added file system.
reverse_iterator overlays_rend() { return FSList.end(); }
const_reverse_iterator overlays_rend() const { return FSList.end(); }
+
+ range overlays_range() { return llvm::reverse(FSList); }
+ const_range overlays_range() const { return llvm::reverse(FSList); }
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
};
/// By default, this delegates all calls to the underlying file system. This
@@ -520,6 +551,10 @@ class InMemoryFileSystem : public FileSystem {
SmallVectorImpl<char> &Output) const override;
std::error_code isLocal(const Twine &Path, bool &Result) override;
std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
};
/// Get a globally unique ID for a virtual file or directory.
@@ -910,12 +945,11 @@ class RedirectingFileSystem : public vfs::FileSystem {
std::vector<llvm::StringRef> getRoots() const;
- void print(raw_ostream &OS) const;
- void printEntry(raw_ostream &OS, Entry *E, int NumSpaces = 0) const;
+ void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel = 0) const;
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- LLVM_DUMP_METHOD void dump() const;
-#endif
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
};
/// Collect all pairs of <virtual path, real path> entries from the
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 1ca18e4b82cb9..cb34fa60d8018 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -151,6 +151,10 @@ bool FileSystem::exists(const Twine &Path) {
return Status && Status->exists();
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void FileSystem::dump() const { print(dbgs(), PrintType::RecursiveContents); }
+#endif
+
#ifndef NDEBUG
static bool isTraversalComponent(StringRef Component) {
return Component.equals("..") || Component.equals(".");
@@ -273,6 +277,10 @@ class RealFileSystem : public FileSystem {
std::error_code getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) const override;
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
+
private:
// If this FS has its own working dir, use it to make Path absolute.
// The returned twine is safe to use as long as both Storage and Path live.
@@ -354,6 +362,17 @@ RealFileSystem::getRealPath(const Twine &Path,
return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
}
+void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "RealFileSystem using ";
+ if (WD)
+ OS << "own";
+ else
+ OS << "process";
+ OS << " CWD\n";
+}
+
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
return FS;
@@ -459,6 +478,19 @@ OverlayFileSystem::getRealPath(const Twine &Path,
return errc::no_such_file_or_directory;
}
+void OverlayFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "OverlayFileSystem\n";
+ if (Type == PrintType::Summary)
+ return;
+
+ if (Type == PrintType::Contents)
+ Type = PrintType::Summary;
+ for (auto FS : overlays_range())
+ FS->print(OS, Type, IndentLevel + 1);
+}
+
llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
namespace {
@@ -1047,6 +1079,12 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
return {};
}
+void InMemoryFileSystem::printImpl(raw_ostream &OS, PrintType PrintContents,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "InMemoryFileSystem\n";
+}
+
} // namespace vfs
} // namespace llvm
@@ -1381,34 +1419,59 @@ std::vector<StringRef> RedirectingFileSystem::getRoots() const {
return R;
}
-void RedirectingFileSystem::print(raw_ostream &OS) const {
+void RedirectingFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "RedirectingFileSystem (UseExternalNames: "
+ << (UseExternalNames ? "true" : "false") << ")\n";
+ if (Type == PrintType::Summary)
+ return;
+
for (const auto &Root : Roots)
- printEntry(OS, Root.get());
+ printEntry(OS, Root.get(), IndentLevel);
+
+ printIndent(OS, IndentLevel);
+ OS << "ExternalFS:\n";
+ ExternalFS->print(OS, Type == PrintType::Contents ? PrintType::Summary : Type,
+ IndentLevel + 1);
}
void RedirectingFileSystem::printEntry(raw_ostream &OS,
RedirectingFileSystem::Entry *E,
- int NumSpaces) const {
- StringRef Name = E->getName();
- for (int i = 0, e = NumSpaces; i < e; ++i)
- OS << " ";
- OS << "'" << Name.str().c_str() << "'"
- << "\n";
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "'" << E->getName() << "'";
- if (E->getKind() == RedirectingFileSystem::EK_Directory) {
- auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(E);
- assert(DE && "Should be a directory");
+ switch (E->getKind()) {
+ case EK_Directory: {
+ auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
+ OS << "\n";
for (std::unique_ptr<Entry> &SubEntry :
llvm::make_range(DE->contents_begin(), DE->contents_end()))
- printEntry(OS, SubEntry.get(), NumSpaces + 2);
+ printEntry(OS, SubEntry.get(), IndentLevel + 1);
+ break;
+ }
+ case EK_DirectoryRemap:
+ case EK_File: {
+ auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
+ OS << " -> '" << RE->getExternalContentsPath() << "'";
+ switch (RE->getUseName()) {
+ case NK_NotSet:
+ break;
+ case NK_External:
+ OS << " (UseExternalName: true)";
+ break;
+ case NK_Virtual:
+ OS << " (UseExternalName: false)";
+ break;
+ }
+ OS << "\n";
+ break;
+ }
}
}
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-void RedirectingFileSystem::dump() const { print(dbgs()); }
-#endif
-
/// A helper class to hold the common YAML parsing state.
class llvm::vfs::RedirectingFileSystemParser {
yaml::Stream &Stream;
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index 657fc0afb7fc4..1eb7fe6b27611 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -171,6 +171,25 @@ class DummyFileSystem : public vfs::FileSystem {
sys::fs::file_type::symlink_file, sys::fs::all_all);
addEntry(Path, S);
}
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override {
+ printIndent(OS, IndentLevel);
+ OS << "DummyFileSystem (";
+ switch (Type) {
+ case vfs::FileSystem::PrintType::Summary:
+ OS << "Summary";
+ break;
+ case vfs::FileSystem::PrintType::Contents:
+ OS << "Contents";
+ break;
+ case vfs::FileSystem::PrintType::RecursiveContents:
+ OS << "RecursiveContents";
+ break;
+ }
+ OS << ")\n";
+ }
};
class ErrorDummyFileSystem : public DummyFileSystem {
@@ -848,6 +867,36 @@ TEST(VirtualFileSystemTest, HiddenInIteration) {
}
}
+TEST(OverlayFileSystemTest, PrintOutput) {
+ auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
+ auto Overlay1 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Dummy);
+ Overlay1->pushOverlay(Dummy);
+ auto Overlay2 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Overlay1);
+ Overlay2->pushOverlay(Dummy);
+
+ SmallString<0> Output;
+ raw_svector_ostream OuputStream{Output};
+
+ Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Summary);
+ ASSERT_EQ("OverlayFileSystem\n", Output);
+
+ Output.clear();
+ Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Contents);
+ ASSERT_EQ("OverlayFileSystem\n"
+ " DummyFileSystem (Summary)\n"
+ " OverlayFileSystem\n",
+ Output);
+
+ Output.clear();
+ Overlay2->print(OuputStream, vfs::FileSystem::PrintType::RecursiveContents);
+ ASSERT_EQ("OverlayFileSystem\n"
+ " DummyFileSystem (RecursiveContents)\n"
+ " OverlayFileSystem\n"
+ " DummyFileSystem (RecursiveContents)\n"
+ " DummyFileSystem (RecursiveContents)\n",
+ Output);
+}
+
TEST(ProxyFileSystemTest, Basic) {
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
new vfs::InMemoryFileSystem());
@@ -2928,3 +2977,80 @@ TEST(VFSFromRemappedFilesTest, LastMappingWins) {
EXPECT_EQ("contents of c", (*BufferKeepA)->getBuffer());
EXPECT_EQ("contents of c", (*BufferExternalA)->getBuffer());
}
+
+TEST(RedirectingFileSystemTest, PrintOutput) {
+ auto Buffer =
+ MemoryBuffer::getMemBuffer("{\n"
+ " 'version': 0,\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory-remap',\n"
+ " 'name': '/dremap',\n"
+ " 'external-contents': '/a',\n"
+ " },"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': '/vdir',\n"
+ " 'contents': ["
+ " {\n"
+ " 'type': 'directory-remap',\n"
+ " 'name': 'dremap',\n"
+ " 'external-contents': '/b'\n"
+ " 'use-external-name': 'true'\n"
+ " },\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': 'vfile',\n"
+ " 'external-contents': '/c'\n"
+ " 'use-external-name': 'false'\n"
+ " }]\n"
+ " }]\n"
+ "}");
+
+ auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
+ auto Redirecting = vfs::RedirectingFileSystem::create(
+ std::move(Buffer), nullptr, "", nullptr, Dummy);
+
+ SmallString<0> Output;
+ raw_svector_ostream OuputStream{Output};
+
+ Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Summary);
+ ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n", Output);
+
+ Output.clear();
+ Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents);
+ ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
+ "'/'\n"
+ " 'dremap' -> '/a'\n"
+ " 'vdir'\n"
+ " 'dremap' -> '/b' (UseExternalName: true)\n"
+ " 'vfile' -> '/c' (UseExternalName: false)\n"
+ "ExternalFS:\n"
+ " DummyFileSystem (Summary)\n",
+ Output);
+
+ Output.clear();
+ Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents, 1);
+ ASSERT_EQ(" RedirectingFileSystem (UseExternalNames: true)\n"
+ " '/'\n"
+ " 'dremap' -> '/a'\n"
+ " 'vdir'\n"
+ " 'dremap' -> '/b' (UseExternalName: true)\n"
+ " 'vfile' -> '/c' (UseExternalName: false)\n"
+ " ExternalFS:\n"
+ " DummyFileSystem (Summary)\n",
+ Output);
+
+ Output.clear();
+ Redirecting->print(OuputStream,
+ vfs::FileSystem::PrintType::RecursiveContents);
+ ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
+ "'/'\n"
+ " 'dremap' -> '/a'\n"
+ " 'vdir'\n"
+ " 'dremap' -> '/b' (UseExternalName: true)\n"
+ " 'vfile' -> '/c' (UseExternalName: false)\n"
+ "ExternalFS:\n"
+ " DummyFileSystem (RecursiveContents)\n",
+ Output);
+}
More information about the llvm-commits
mailing list