struct YAMLVFSEntry {
template <typename T1, typename T2>
- YAMLVFSEntry(T1 &&VPath, T2 &&RPath)
- : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
+ YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false)
+ : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)),
+ IsDirectory(IsDirectory) {}
std::string VPath;
std::string RPath;
+ bool IsDirectory = false;
};
class VFSFromYamlDirIterImpl;
Optional<bool> UseExternalNames;
std::string OverlayDir;
+ void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory);
+
public:
YAMLVFSWriter() = default;
void addFileMapping(StringRef VirtualPath, StringRef RealPath);
+ void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath);
void setCaseSensitivity(bool CaseSensitive) {
IsCaseSensitive = CaseSensitive;
return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
}
-void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
+ bool IsDirectory) {
assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
assert(sys::path::is_absolute(RealPath) && "real path not absolute");
assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
- Mappings.emplace_back(VirtualPath, RealPath);
+ Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
+}
+
+void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+ addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
+}
+
+void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath,
+ StringRef RealPath) {
+ addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
}
namespace {
if (!Entries.empty()) {
const YAMLVFSEntry &Entry = Entries.front();
- startDirectory(path::parent_path(Entry.VPath));
+ bool first_entry_is_directory = Entry.IsDirectory;
+ StringRef Dir =
+ first_entry_is_directory ? Entry.VPath : path::parent_path(Entry.VPath);
+ startDirectory(Dir);
StringRef RPath = Entry.RPath;
if (UseOverlayRelative) {
RPath = RPath.slice(OverlayDirLen, RPath.size());
}
- writeEntry(path::filename(Entry.VPath), RPath);
+ if (!first_entry_is_directory)
+ writeEntry(path::filename(Entry.VPath), RPath);
for (const auto &Entry : Entries.slice(1)) {
- StringRef Dir = path::parent_path(Entry.VPath);
- if (Dir == DirStack.back())
- OS << ",\n";
- else {
+ StringRef Dir =
+ Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
+ if (Dir == DirStack.back()) {
+ if (!first_entry_is_directory) {
+ OS << ",\n";
+ first_entry_is_directory = false;
+ }
+ } else {
while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
OS << "\n";
endDirectory();
ScopedDir _g(TestDirectory + "/g");
ScopedFile _h(TestDirectory + "/h", "");
- // This test exposes a bug/shortcoming in the YAMLVFSWriter. Below we call
- // addFileMapping for _a and _e, which causes _ab and _ef not to exists in
- // the deserialized file system, because _a and _e got emitted as regular
- // files. The counter example is _c, if we only call addFileMapping for _cd,
- // things work as expected.
-
vfs::YAMLVFSWriter VFSWriter;
- VFSWriter.addFileMapping(_a.Path, "//root/a");
+ VFSWriter.addDirectoryMapping(_a.Path, "//root/a");
VFSWriter.addFileMapping(_ab.Path, "//root/a/b");
VFSWriter.addFileMapping(_cd.Path, "//root/c/d");
- VFSWriter.addFileMapping(_e.Path, "//root/e");
- VFSWriter.addFileMapping(_ef.Path, "//root/e/f");
+ VFSWriter.addDirectoryMapping(_e.Path, "//root/e");
+ VFSWriter.addDirectoryMapping(_ef.Path, "//root/e/f");
VFSWriter.addFileMapping(_g.Path, "//root/g");
- VFSWriter.addFileMapping(_h.Path, "//root/h");
+ VFSWriter.addDirectoryMapping(_h.Path, "//root/h");
std::string Buffer;
raw_string_ostream OS(Buffer);
ASSERT_TRUE(FS.get() != nullptr);
EXPECT_TRUE(FS->exists(_a.Path));
- EXPECT_FALSE(FS->exists(_ab.Path)); // FIXME: See explanation above.
+ EXPECT_TRUE(FS->exists(_ab.Path));
EXPECT_TRUE(FS->exists(_c.Path));
EXPECT_TRUE(FS->exists(_cd.Path));
EXPECT_TRUE(FS->exists(_e.Path));
- EXPECT_FALSE(FS->exists(_ef.Path)); // FIXME: See explanation above.
+ EXPECT_TRUE(FS->exists(_ef.Path));
EXPECT_TRUE(FS->exists(_g.Path));
EXPECT_TRUE(FS->exists(_h.Path));
}