Commit 54bd7398 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

fix folly::fs::lexically_normal

Summary:
Make the implementation of `folly::fs::lexically_normal` match C++17 `std::filesystem::path::lexically_normal`. The implementation from `boost::filesystem::path::lexically_normal` is easy to fall back on but has some differences.

The implementation is copied mutatis mutandis from https://github.com/gulrak/filesystem/ at tag v1.5.0, in which `ghc::filesystem` is a complete portable standalone implementation of the `std::filesystem` spec and released under the MIT license.

Reviewed By: Orvid

Differential Revision: D26572520

fbshipit-source-id: 5ce03f37c078ee4f62e3480d4abc259199867c8e
parent 9c47cb9c
...@@ -16,12 +16,8 @@ ...@@ -16,12 +16,8 @@
#include <folly/portability/Filesystem.h> #include <folly/portability/Filesystem.h>
#include <boost/filesystem.hpp>
namespace folly::fs { namespace folly::fs {
namespace boost_fs = boost::filesystem;
#if __cpp_lib_filesystem >= 201703 #if __cpp_lib_filesystem >= 201703
path lexically_normal_fn::operator()(path const& p) const { path lexically_normal_fn::operator()(path const& p) const {
...@@ -30,8 +26,38 @@ path lexically_normal_fn::operator()(path const& p) const { ...@@ -30,8 +26,38 @@ path lexically_normal_fn::operator()(path const& p) const {
#elif __cpp_lib_experimental_filesystem >= 201406 #elif __cpp_lib_experimental_filesystem >= 201406
// mimic: std::filesystem::path::lexically_normal, C++17
// from: https://github.com/gulrak/filesystem/tree/v1.5.0, MIT
path lexically_normal_fn::operator()(path const& p) const { path lexically_normal_fn::operator()(path const& p) const {
return path(boost_fs::path(p.native()).lexically_normal().native()); path dest;
bool lastDotDot = false;
for (path::string_type s : p) {
if (s == ".") {
dest /= "";
continue;
} else if (s == ".." && !dest.empty()) {
auto root = p.root_path();
if (dest == root) {
continue;
} else if (*(--dest.end()) != "..") {
auto drepr = dest.native();
if (drepr.back() == path::preferred_separator) {
drepr.pop_back();
dest = std::move(drepr);
}
dest.remove_filename();
continue;
}
}
if (!(s.empty() && lastDotDot)) {
dest /= s;
}
lastDotDot = s == "..";
}
if (dest.empty()) {
dest = ".";
}
return dest;
} }
#else #else
......
...@@ -24,14 +24,12 @@ using namespace testing; ...@@ -24,14 +24,12 @@ using namespace testing;
class FilesystemTest : public Test {}; class FilesystemTest : public Test {};
TEST_F(FilesystemTest, lexically_normal) { TEST_F(FilesystemTest, lexically_normal) {
// cases from cppreference.com // from: https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal,
// implementation either std::filesystem or boost::filesystem // CC-BY-SA, GFDL
auto gold = folly::fs::which == folly::fs::which_enum::std;
auto sep = std::string({folly::fs::path::preferred_separator});
EXPECT_THAT( EXPECT_THAT(
folly::fs::lexically_normal("foo/./bar/..").native(), folly::fs::lexically_normal("foo/./bar/..").native(),
Eq(folly::fs::path(gold ? "foo" + sep : "foo").native())); Eq(folly::fs::path("foo/").make_preferred().native()));
EXPECT_THAT( EXPECT_THAT(
folly::fs::lexically_normal("foo/.///bar/../").native(), folly::fs::lexically_normal("foo/.///bar/../").native(),
Eq(folly::fs::path(gold ? "foo" + sep : "foo" + sep + ".").native())); Eq(folly::fs::path("foo/").make_preferred().native()));
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment