diff --git a/clang/lib/CAS/IncludeTree.cpp b/clang/lib/CAS/IncludeTree.cpp index 8cb2ad4c2de7d..3613bd478328c 100644 --- a/clang/lib/CAS/IncludeTree.cpp +++ b/clang/lib/CAS/IncludeTree.cpp @@ -1039,6 +1039,26 @@ class IncludeTreeFileSystem final : public llvm::cas::CASBackedFileSystem { createThreadSafeProxyFS() override { llvm::report_fatal_error("not implemented"); } + + void printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const final { + printIndent(OS, IndentLevel); + IndentLevel += 1; + OS << "IncludeTreeFileSystem\n"; + if (Type == PrintType::Summary) + return; + + // Files is unordered, so sort by name to get a deterministic order. + std::vector> FileRefs; + for (auto &[Name, F] : Files) + FileRefs.emplace_back(Name, F.ContentsRef); + llvm::sort(FileRefs, [](auto &&A, auto &&B) { return A.first < B.first; }); + + for (auto &[Name, ContentsRef] : FileRefs) { + printIndent(OS, IndentLevel); + OS << Name << ' ' << CAS.getID(ContentsRef) << '\n'; + } + } }; } // namespace diff --git a/clang/unittests/CAS/IncludeTreeTest.cpp b/clang/unittests/CAS/IncludeTreeTest.cpp index 88b68a523043f..cad02ac228226 100644 --- a/clang/unittests/CAS/IncludeTreeTest.cpp +++ b/clang/unittests/CAS/IncludeTreeTest.cpp @@ -296,27 +296,29 @@ TEST(IncludeTree, IncludeTreeFileListDuplicates) { EXPECT_EQ(I, Files.size()); } -TEST(IncludeTree, IncludeTreeFileSystemOverlay) { - StringRef PathSep = llvm::sys::path::get_separator(); - std::shared_ptr DB = llvm::cas::createInMemoryCAS(); +static Expected> +createTestInclueTreeFS(ObjectStore &DB, unsigned NumFiles = 10) { SmallVector Files; - for (unsigned I = 0; I < 10; ++I) { + for (unsigned I = 0; I < NumFiles; ++I) { std::optional File; std::string Path = "/file" + std::to_string(I); static constexpr StringRef Bytes = "123456789"; std::optional Content; - ASSERT_THAT_ERROR( - DB->storeFromString({}, Bytes.substr(0, I)).moveInto(Content), - llvm::Succeeded()); - ASSERT_THAT_ERROR( - IncludeTree::File::create(*DB, Path, *Content).moveInto(File), - llvm::Succeeded()); + if (auto E = DB.storeFromString({}, Bytes.substr(0, I)).moveInto(Content)) + return std::move(E); + if (auto E = IncludeTree::File::create(DB, Path, *Content).moveInto(File)) + return std::move(E); Files.push_back({File->getRef(), I}); } + return createIncludeTreeFileSystem(DB, Files); +} + +TEST(IncludeTree, IncludeTreeFileSystemOverlay) { + StringRef PathSep = llvm::sys::path::get_separator(); + std::shared_ptr DB = llvm::cas::createInMemoryCAS(); IntrusiveRefCntPtr IncludeTreeFS; - ASSERT_THAT_ERROR( - createIncludeTreeFileSystem(*DB, Files).moveInto(IncludeTreeFS), - llvm::Succeeded()); + ASSERT_THAT_ERROR(createTestInclueTreeFS(*DB).moveInto(IncludeTreeFS), + llvm::Succeeded()); auto FS = llvm::makeIntrusiveRefCnt(); FS->setCurrentWorkingDirectory("/dir"); @@ -338,3 +340,32 @@ TEST(IncludeTree, IncludeTreeFileSystemOverlay) { } ASSERT_EQ(NumFile, 2); } + +TEST(IncludeTree, IncludeTreeFileSystemPrint) { + std::shared_ptr DB = llvm::cas::createInMemoryCAS(); + IntrusiveRefCntPtr IncludeTreeFS; + ASSERT_THAT_ERROR( + createTestInclueTreeFS(*DB, /*NumFiles=*/3).moveInto(IncludeTreeFS), + llvm::Succeeded()); + + { + std::string FSStr; + llvm::raw_string_ostream OS(FSStr); + IncludeTreeFS->print(OS, llvm::vfs::FileSystem::PrintType::Summary); + EXPECT_EQ(FSStr, "IncludeTreeFileSystem\n"); + } + { + std::string FSStr; + llvm::raw_string_ostream OS(FSStr); + IncludeTreeFS->print(OS, llvm::vfs::FileSystem::PrintType::Contents); + StringRef Printed(FSStr); + EXPECT_TRUE(Printed.consume_front("IncludeTreeFileSystem")) << Printed; + EXPECT_TRUE(Printed.consume_front("\n /file0 llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_TRUE(Printed.consume_front("\n /file1 llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_TRUE(Printed.consume_front("\n /file2 llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_EQ(Printed, "\n"); // Final newline. + } +} diff --git a/llvm/lib/CAS/CASFileSystem.cpp b/llvm/lib/CAS/CASFileSystem.cpp index 4485498bbad8f..83749d19652a1 100644 --- a/llvm/lib/CAS/CASFileSystem.cpp +++ b/llvm/lib/CAS/CASFileSystem.cpp @@ -96,6 +96,9 @@ class CASFileSystem final return WorkingDirectory.Path; } + void printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const final; + Error initialize(ObjectRef Root); CASFileSystem(std::shared_ptr DB, sys::path::Style PathStyle) @@ -184,6 +187,45 @@ std::error_code CASFileSystem::setCurrentWorkingDirectory(const Twine &Path) { return std::error_code(); } +void CASFileSystem::printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const { + printIndent(OS, IndentLevel); + OS << "CASFileSystem\n"; + if (Type == PrintType::Summary) + return; + + IndentLevel += 1; + printIndent(OS, IndentLevel); + StringRef path_separator = get_separator(PathStyle); + auto &Root = Cache->getRoot(path_separator); + OS << "root: " << Root.getTreePath(); + assert(Root.getRef() && "missing ID for primary CASFileSystem root"); + if (Root.getRef()) + OS << ' ' << DB.getID(*Root.getRef()) << '\n'; + + if (Type == PrintType::Contents) + return; + + IndentLevel += 1; + TreeSchema Schema(DB); + auto TreeN = DB.getProxy(*Root.getRef()); + if (!TreeN) { + OS << toString(TreeN.takeError()) << '\n'; + return; + } + Error E = Schema.walkFileTreeRecursively( + DB, TreeN->getRef(), + [&](const NamedTreeEntry &Entry, std::optional Tree) -> Error { + if (Entry.getKind() != TreeEntry::Tree) { + printIndent(OS, IndentLevel); + Entry.print(OS, DB); + } + return Error::success(); + }); + if (E) + OS << toString(std::move(E)) << '\n'; +} + Error CASFileSystem::loadDirectory(DirectoryEntry &Parent) { Directory &D = Parent.asDirectory(); if (D.isComplete()) diff --git a/llvm/lib/CAS/CachingOnDiskFileSystem.cpp b/llvm/lib/CAS/CachingOnDiskFileSystem.cpp index 3b9c6089fcbb3..c04abc8785939 100644 --- a/llvm/lib/CAS/CachingOnDiskFileSystem.cpp +++ b/llvm/lib/CAS/CachingOnDiskFileSystem.cpp @@ -121,6 +121,9 @@ class CachingOnDiskFileSystemImpl final : public CachingOnDiskFileSystem { return makeIntrusiveRefCnt(*this); } + void printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const final; + CachingOnDiskFileSystemImpl(std::shared_ptr DB) : CachingOnDiskFileSystem(std::move(DB)) { initializeWorkingDirectory(); @@ -894,6 +897,13 @@ CachingOnDiskFileSystemImpl::createTreeBuilder() { return std::make_unique(*this); } +void CachingOnDiskFileSystemImpl::printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const { + printIndent(OS, IndentLevel); + OS << "CachingOnDiskFileSystem\n"; + // FIXME: print contents +} + void CachingOnDiskFileSystemImpl::TreeBuilder::pushSymlink( const DirectoryEntry &Entry) { assert(Entry.isSymlink()); diff --git a/llvm/unittests/CAS/CASFileSystemTest.cpp b/llvm/unittests/CAS/CASFileSystemTest.cpp index ad6342baa5499..714d54de2d148 100644 --- a/llvm/unittests/CAS/CASFileSystemTest.cpp +++ b/llvm/unittests/CAS/CASFileSystemTest.cpp @@ -516,3 +516,46 @@ TEST(CASFileSystemTest, recursiveDirectoryIteratorNested) { sys::fs::file_type::regular_file)); ASSERT_TRUE(isEnd(D, EC)); } + +TEST(CASFileSystemTest, print) { + std::unique_ptr CAS = createInMemoryCAS(); + ASSERT_TRUE(CAS); + std::optional Tree; + ASSERT_THAT_ERROR(createNestedTree(*CAS).moveInto(Tree), Succeeded()); + std::unique_ptr CASFS; + ASSERT_THAT_ERROR(createFS(*CAS, *Tree).moveInto(CASFS), Succeeded()); + + { + std::string FSStr; + llvm::raw_string_ostream OS(FSStr); + CASFS->print(OS, vfs::FileSystem::PrintType::Summary); + EXPECT_EQ(FSStr, "CASFileSystem\n"); + } + { + std::string FSStr; + llvm::raw_string_ostream OS(FSStr); + CASFS->print(OS, vfs::FileSystem::PrintType::Contents); + std::string Expected = "CASFileSystem\n"; + Expected += " root: / " + Tree->getID().toString() + "\n"; + EXPECT_EQ(FSStr, Expected); + } + { + std::string FSStr; + llvm::raw_string_ostream OS(FSStr); + CASFS->print(OS, vfs::FileSystem::PrintType::RecursiveContents); + std::string Expected = "CASFileSystem\n"; + Expected += " root: / " + Tree->getID().toString() + "\n"; + StringRef Printed(FSStr); + EXPECT_TRUE(Printed.consume_front("CASFileSystem")) << Printed; + EXPECT_TRUE(Printed.consume_front("\n root: / llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_TRUE(Printed.consume_front("\n file llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_TRUE(Printed.consume_front(" /d2")) << Printed; + EXPECT_TRUE(Printed.consume_front("\n file llvmcas://")) << Printed; + Printed = Printed.drop_front(64); // 32 hash bytes in hex + EXPECT_TRUE(Printed.consume_front(" /t1/d1\n")) << Printed; + // ... + EXPECT_TRUE(Printed.consume_back("/t3/t2/d2\n")) << Printed; + } +}