Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VirtualFileSystem] Support virtual working directory in the RedirectingFS #11

Merged
merged 9 commits into from
Oct 28, 2019
26 changes: 22 additions & 4 deletions llvm/include/llvm/Support/VirtualFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,24 @@ class OverlayFileSystem : public FileSystem {

using iterator = FileSystemList::reverse_iterator;
using const_iterator = FileSystemList::const_reverse_iterator;
using reverse_iterator = FileSystemList::iterator;
using const_reverse_iterator = FileSystemList::const_iterator;

/// Get an iterator pointing to the most recently added file system.
iterator overlays_begin() { return FSList.rbegin(); }
const_iterator overlays_begin() const { return FSList.rbegin(); }

/// Get an iterator pointing one-past the least recently added file
/// system.
/// Get an iterator pointing one-past the least recently added file system.
iterator overlays_end() { return FSList.rend(); }
const_iterator overlays_end() const { return FSList.rend(); }

/// Get an iterator pointing to the least recently added file system.
reverse_iterator overlays_rbegin() { return FSList.begin(); }
const_reverse_iterator overlays_rbegin() const { return FSList.begin(); }

/// 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(); }
};

/// By default, this delegates all calls to the underlying file system. This
Expand Down Expand Up @@ -638,9 +647,19 @@ class RedirectingFileSystem : public vfs::FileSystem {
friend class VFSFromYamlDirIterImpl;
friend class RedirectingFileSystemParser;

bool shouldUseExternalFS() const {
return ExternalFSValidWD && IsFallthrough;
}

/// The root(s) of the virtual file system.
std::vector<std::unique_ptr<Entry>> Roots;

/// The current working directory of the file system.
std::string WorkingDirectory;

/// Whether the current working directory is valid for the external FS.
bool ExternalFSValidWD = false;

/// The file system to use for external references.
IntrusiveRefCntPtr<FileSystem> ExternalFS;

Expand Down Expand Up @@ -680,8 +699,7 @@ class RedirectingFileSystem : public vfs::FileSystem {
true;
#endif

RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
: ExternalFS(std::move(ExternalFS)) {}
RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);

/// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
/// recursing into the contents of \p From if it is a directory.
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,11 +855,11 @@ void make_absolute(const Twine &current_directory,
StringRef p(path.data(), path.size());

bool rootDirectory = path::has_root_directory(p);
bool rootName =
(real_style(Style::native) != Style::windows) || path::has_root_name(p);
bool rootName = path::has_root_name(p);

// Already absolute.
if (rootName && rootDirectory)
if ((rootName || real_style(Style::native) != Style::windows) &&
rootDirectory)
return;

// All of the following conditions will need the current directory.
Expand Down
58 changes: 40 additions & 18 deletions llvm/lib/Support/VirtualFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,16 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
// RedirectingFileSystem implementation
//===-----------------------------------------------------------------------===/

RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
: ExternalFS(std::move(FS)) {
if (ExternalFS)
if (auto ExternalWorkingDirectory =
ExternalFS->getCurrentWorkingDirectory()) {
WorkingDirectory = *ExternalWorkingDirectory;
ExternalFSValidWD = true;
}
}

// FIXME: reuse implementation common with OverlayFSDirIterImpl as these
// iterators are conceptually similar.
class llvm::vfs::VFSFromYamlDirIterImpl
Expand Down Expand Up @@ -1032,12 +1042,27 @@ class llvm::vfs::VFSFromYamlDirIterImpl

llvm::ErrorOr<std::string>
RedirectingFileSystem::getCurrentWorkingDirectory() const {
return ExternalFS->getCurrentWorkingDirectory();
return WorkingDirectory;
}

std::error_code
RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
return ExternalFS->setCurrentWorkingDirectory(Path);
// Don't change the working directory if the path doesn't exist.
if (!exists(Path))
return errc::no_such_file_or_directory;

// Always change the external FS but ignore its result.
if (ExternalFS) {
auto EC = ExternalFS->setCurrentWorkingDirectory(Path);
ExternalFSValidWD = !static_cast<bool>(EC);
}

SmallString<128> AbsolutePath;
Path.toVector(AbsolutePath);
if (std::error_code EC = makeAbsolute(AbsolutePath))
return EC;
WorkingDirectory = AbsolutePath.str();
return {};
}

std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
Expand All @@ -1050,7 +1075,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir);
if (!E) {
EC = E.getError();
if (IsFallthrough && EC == errc::no_such_file_or_directory)
if (shouldUseExternalFS() && EC == errc::no_such_file_or_directory)
return ExternalFS->dir_begin(Dir, EC);
return {};
}
Expand All @@ -1068,7 +1093,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E);
return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
Dir, D->contents_begin(), D->contents_end(),
/*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
/*IterateExternalFS=*/shouldUseExternalFS(), *ExternalFS, EC));
}

void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
Expand Down Expand Up @@ -1218,7 +1243,7 @@ class llvm::vfs::RedirectingFileSystemParser {
}

auto *DE =
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
DE->addContent(std::move(E));
return DE->getLastContent();
}
Expand All @@ -1229,9 +1254,7 @@ class llvm::vfs::RedirectingFileSystemParser {
StringRef Name = SrcE->getName();
switch (SrcE->getKind()) {
case RedirectingFileSystem::EK_Directory: {
auto *DE =
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
assert(DE && "Must be a directory");
auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
// Empty directories could be present in the YAML as a way to
// describe a file for a current directory after some of its subdir
// is parsed. This only leads to redundant walks, ignore it.
Expand All @@ -1243,11 +1266,10 @@ class llvm::vfs::RedirectingFileSystemParser {
break;
}
case RedirectingFileSystem::EK_File: {
auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
assert(FE && "Must be a file");
assert(NewParentE && "Parent entry must exist");
auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
NewParentE);
auto *FE = cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
auto *DE =
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(NewParentE);
DE->addContent(
llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
Name, FE->getExternalContentsPath(), FE->getUseName()));
Expand Down Expand Up @@ -1570,7 +1592,7 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
RedirectingFileSystemParser P(Stream);

std::unique_ptr<RedirectingFileSystem> FS(
new RedirectingFileSystem(std::move(ExternalFS)));
new RedirectingFileSystem(ExternalFS));

if (!YAMLFilePath.empty()) {
// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
Expand Down Expand Up @@ -1699,7 +1721,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->status(Path);
}
Expand Down Expand Up @@ -1737,7 +1759,7 @@ ErrorOr<std::unique_ptr<File>>
RedirectingFileSystem::openFileForRead(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
if (!E) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
E.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->openFileForRead(Path);
}
Expand Down Expand Up @@ -1768,7 +1790,7 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) const {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->getRealPath(Path, Output);
}
Expand All @@ -1781,8 +1803,8 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
}
// Even if there is a directory entry, fall back to ExternalFS if allowed,
// because directories don't have a single external contents path.
return IsFallthrough ? ExternalFS->getRealPath(Path, Output)
: llvm::errc::invalid_argument;
return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
: llvm::errc::invalid_argument;
}

IntrusiveRefCntPtr<FileSystem>
Expand Down
17 changes: 13 additions & 4 deletions llvm/unittests/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,19 @@ TEST(Support, Path) {
path::native(*i, temp_store);
}

SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("/root", Relative);
Relative[5] = '/'; // Fix up windows paths.
ASSERT_EQ("/root/foo.cpp", Relative);
{
SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("/root", Relative);
Relative[5] = '/'; // Fix up windows paths.
ASSERT_EQ("/root/foo.cpp", Relative);
}

{
SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("//root", Relative);
Relative[6] = '/'; // Fix up windows paths.
ASSERT_EQ("//root/foo.cpp", Relative);
}
}

TEST(Support, FilenameParent) {
Expand Down
Loading