JDevlieghere updated this revision to Diff 217487.
JDevlieghere retitled this revision from "[VirtualFileSystem] Support encoding 
a current working directory in a VFS mapping." to "[VirtualFileSystem] Support 
encoding working directories in a VFS mapping.".
JDevlieghere added a comment.

Support multiple working directories.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D65677/new/

https://reviews.llvm.org/D65677

Files:
  llvm/include/llvm/Support/VirtualFileSystem.h
  llvm/lib/Support/VirtualFileSystem.cpp
  llvm/unittests/Support/VirtualFileSystemTest.cpp

Index: llvm/unittests/Support/VirtualFileSystemTest.cpp
===================================================================
--- llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -1994,3 +1994,108 @@
   EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
             errc::no_such_file_or_directory);
 }
+
+TEST_F(VFSFromYAMLTest, WorkingDirectoriesOneMatch) {
+  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+  Lower->addDirectory("//root/");
+  Lower->addDirectory("//root/foo");
+  Lower->addRegularFile("//root/foo/a");
+  Lower->addRegularFile("//root/foo/b");
+  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+      "{ 'use-external-names': false,\n"
+      "  'working-directories': ['//root/quux/', '//root/bar']\n"
+      "  'roots': [\n"
+      "{\n"
+      "  'type': 'directory',\n"
+      "  'name': '//root/',\n"
+      "  'contents': [ {\n"
+      "                  'type': 'file',\n"
+      "                  'name': 'bar/a',\n"
+      "                  'external-contents': '//root/foo/a'\n"
+      "                }\n"
+      "              ]\n"
+      "}\n"
+      "]\n"
+      "}",
+      Lower);
+  ASSERT_TRUE(FS.get() != nullptr);
+
+  llvm::ErrorOr<vfs::Status> Status = FS->status("./a");
+  ASSERT_FALSE(Status.getError());
+  EXPECT_TRUE(Status->isStatusKnown());
+  EXPECT_FALSE(Status->isDirectory());
+  EXPECT_TRUE(Status->isRegularFile());
+  EXPECT_FALSE(Status->isSymlink());
+  EXPECT_FALSE(Status->isOther());
+  EXPECT_TRUE(Status->exists());
+}
+
+TEST_F(VFSFromYAMLTest, WorkingDirectoriesNoMatch) {
+  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+  Lower->addDirectory("//root/");
+  Lower->addDirectory("//root/foo");
+  Lower->addRegularFile("//root/foo/a");
+  Lower->addRegularFile("//root/foo/b");
+  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+      "{ 'use-external-names': false,\n"
+      "  'working-directories': ['//root/foo/', '//root/quux/']\n"
+      "  'roots': [\n"
+      "{\n"
+      "  'type': 'directory',\n"
+      "  'name': '//root/',\n"
+      "  'contents': [ {\n"
+      "                  'type': 'file',\n"
+      "                  'name': 'bar/a',\n"
+      "                  'external-contents': '//root/foo/a'\n"
+      "                }\n"
+      "              ]\n"
+      "}\n"
+      "]\n"
+      "}",
+      Lower);
+  ASSERT_TRUE(FS.get() != nullptr);
+
+  llvm::ErrorOr<vfs::Status> Status = FS->status("./a");
+  ASSERT_TRUE(Status.getError());
+}
+
+TEST_F(VFSFromYAMLTest, WorkingDirectoriesMultipleMatches) {
+  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+  Lower->addDirectory("//root/");
+  Lower->addDirectory("//root/foo");
+  Lower->addRegularFile("//root/foo/a", sys::fs::owner_read);
+  Lower->addRegularFile("//root/foo/b", sys::fs::owner_write);
+  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+      "{ 'use-external-names': false,\n"
+      "  'working-directories': ['//root/bar/', '//root/baz/']\n"
+      "  'roots': [\n"
+      "{\n"
+      "  'type': 'directory',\n"
+      "  'name': '//root/',\n"
+      "  'contents': [ {\n"
+      "                  'type': 'file',\n"
+      "                  'name': 'bar/a',\n"
+      "                  'external-contents': '//root/foo/a'\n"
+      "                },\n"
+      "                {\n"
+      "                  'type': 'file',\n"
+      "                  'name': 'bar/a',\n"
+      "                  'external-contents': '//root/foo/b'\n"
+      "                }\n"
+      "              ]\n"
+      "}\n"
+      "]\n"
+      "}",
+      Lower);
+  ASSERT_TRUE(FS.get() != nullptr);
+
+  llvm::ErrorOr<vfs::Status> Status = FS->status("./a");
+  ASSERT_FALSE(Status.getError());
+  EXPECT_TRUE(Status->isStatusKnown());
+  EXPECT_FALSE(Status->isDirectory());
+  EXPECT_TRUE(Status->isRegularFile());
+  EXPECT_FALSE(Status->isSymlink());
+  EXPECT_FALSE(Status->isOther());
+  EXPECT_TRUE(Status->exists());
+  EXPECT_EQ(Status->getPermissions(), sys::fs::owner_read);
+}
Index: llvm/lib/Support/VirtualFileSystem.cpp
===================================================================
--- llvm/lib/Support/VirtualFileSystem.cpp
+++ llvm/lib/Support/VirtualFileSystem.cpp
@@ -1043,6 +1043,10 @@
   return ExternalFS->setCurrentWorkingDirectory(Path);
 }
 
+void RedirectingFileSystem::addWorkingDirectory(const Twine &Path) {
+  WorkingDirs.push_back(Path.str());
+}
+
 std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
                                                bool &Result) {
   return ExternalFS->isLocal(Path, Result);
@@ -1473,6 +1477,7 @@
         KeyStatusPair("use-external-names", false),
         KeyStatusPair("overlay-relative", false),
         KeyStatusPair("fallthrough", false),
+        KeyStatusPair("working-directories", false),
         KeyStatusPair("roots", true),
     };
 
@@ -1533,11 +1538,23 @@
       } else if (Key == "fallthrough") {
         if (!parseScalarBool(I.getValue(), FS->IsFallthrough))
           return false;
+      } else if (Key == "working-directories") {
+        auto *Dirs = dyn_cast<yaml::SequenceNode>(I.getValue());
+        if (!Dirs) {
+          error(I.getValue(), "expected array");
+          return false;
+        }
+        SmallString<256> Storage;
+        StringRef WorkingDir;
+        for (auto &I : *Dirs) {
+          if (!parseScalarString(&I, WorkingDir, Storage))
+            return false;
+          FS->addWorkingDirectory(WorkingDir);
+        }
       } else {
         llvm_unreachable("key missing from Keys");
       }
     }
-
     if (Stream.failed())
       return false;
 
@@ -1599,12 +1616,42 @@
 
 ErrorOr<RedirectingFileSystem::Entry *>
 RedirectingFileSystem::lookupPath(const Twine &Path_) const {
+  // First try the current working directory.
+  ErrorOr<RedirectingFileSystem::Entry *> Entry = lookupPathImpl(Path_, true);
+  if (Entry)
+    return Entry;
+
+  // Try the working directories in order.
+  SmallString<256> Storage;
+  for (const std::string &WD : WorkingDirs) {
+    // Initialize the buffer to the given path and resolve it against the
+    // working directory.
+    Storage.clear();
+    Path_.toVector(Storage);
+    sys::fs::make_absolute(WD, Storage);
+
+    // We know that the given path is absolute, so no need to resolve it again
+    // in lookupPathImpl.
+    ErrorOr<RedirectingFileSystem::Entry *> RemappedEntry =
+        lookupPathImpl(Storage, false);
+    if (RemappedEntry)
+      return RemappedEntry;
+  }
+
+  // If nothing was found, return the original error.
+  return Entry;
+}
+
+ErrorOr<RedirectingFileSystem::Entry *>
+RedirectingFileSystem::lookupPathImpl(const Twine &Path_,
+                                      bool MakeAbsolute) const {
   SmallString<256> Path;
   Path_.toVector(Path);
 
   // Handle relative paths
-  if (std::error_code EC = makeAbsolute(Path))
-    return EC;
+  if (MakeAbsolute)
+    if (std::error_code EC = makeAbsolute(Path))
+      return EC;
 
   // Canonicalize path by removing ".", "..", "./", etc components. This is
   // a VFS request, do bot bother about symlinks in the path components
Index: llvm/include/llvm/Support/VirtualFileSystem.h
===================================================================
--- llvm/include/llvm/Support/VirtualFileSystem.h
+++ llvm/include/llvm/Support/VirtualFileSystem.h
@@ -650,6 +650,9 @@
   /// The root(s) of the virtual file system.
   std::vector<std::unique_ptr<Entry>> Roots;
 
+  /// The working directories of this virtual file system.
+  std::vector<std::string> WorkingDirs;
+
   /// The file system to use for external references.
   IntrusiveRefCntPtr<FileSystem> ExternalFS;
 
@@ -692,6 +695,8 @@
   RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
       : ExternalFS(std::move(ExternalFS)) {}
 
+  ErrorOr<Entry *> lookupPathImpl(const Twine &Path, bool MakeAbsolute) const;
+
   /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
   /// recursing into the contents of \p From if it is a directory.
   ErrorOr<Entry *> lookupPath(llvm::sys::path::const_iterator Start,
@@ -722,6 +727,8 @@
 
   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
 
+  void addWorkingDirectory(const Twine &Path);
+
   std::error_code isLocal(const Twine &Path, bool &Result) override;
 
   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to