This is an automated email from the ASF dual-hosted git repository. bennoe pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 12e4ee81599f1b696f501901d246002310dcb9c1 Author: Benjamin Bannier <[email protected]> AuthorDate: Tue Jan 7 13:19:31 2020 +0100 Added a stout function to compute relative paths. Review: https://reviews.apache.org/r/71882/ --- 3rdparty/stout/include/stout/path.hpp | 68 +++++++++++++++++++++++++++++++++++ 3rdparty/stout/tests/path_tests.cpp | 24 +++++++++++++ 2 files changed, 92 insertions(+) diff --git a/3rdparty/stout/include/stout/path.hpp b/3rdparty/stout/include/stout/path.hpp index 06a8a55..14a0d4e 100644 --- a/3rdparty/stout/include/stout/path.hpp +++ b/3rdparty/stout/include/stout/path.hpp @@ -515,4 +515,72 @@ inline std::ostream& operator<<( return stream << path.string(); } + +namespace path { + +// Compute path of `path` relative to `base`. +inline Try<std::string> relative( + const std::string& path_, + const std::string& base_, + char path_separator = os::PATH_SEPARATOR) +{ + if (path::is_absolute(path_) != path::is_absolute(base_)) { + return Error( + "Relative paths can only be computed between paths which are either " + "both absolute or both relative"); + } + + // Normalize both `path` and `base`. + Try<std::string> normalized_path = path::normalize(path_); + Try<std::string> normalized_base = path::normalize(base_); + + if (normalized_path.isError()) { + return normalized_path; + } + + if (normalized_base.isError()) { + return normalized_base; + } + + // If normalized `path` and `base` are identical return `.`. + if (*normalized_path == *normalized_base) { + return "."; + } + + const Path path(*normalized_path); + const Path base(*normalized_base); + + auto path_it = path.begin(); + auto base_it = base.begin(); + + const auto path_end = path.end(); + const auto base_end = base.end(); + + // Strip common path components. + for (; path_it != path_end && base_it != base_end && *path_it == *base_it; + ++path_it, ++base_it) { + } + + std::vector<std::string> result; + result.reserve( + std::distance(base_it, base_end) + std::distance(path_it, path_end)); + + // If we have not fully consumed the range of `base` we need to go + // up from `path` to reach `base`. Insert ".." into the result. + if (base_it != base_end) { + for (; base_it != base_end; ++base_it) { + result.emplace_back(".."); + } + } + + // Add remaining path components to the result. + for (; path_it != path_end; ++path_it) { + result.emplace_back(*path_it); + } + + return join(result, path_separator); +} + +} // namespace path { + #endif // __STOUT_PATH_HPP__ diff --git a/3rdparty/stout/tests/path_tests.cpp b/3rdparty/stout/tests/path_tests.cpp index c5135a4..d418d1b 100644 --- a/3rdparty/stout/tests/path_tests.cpp +++ b/3rdparty/stout/tests/path_tests.cpp @@ -354,6 +354,30 @@ TEST(PathTest, IsAbsolute) } +TEST(PathTest, Relative) +{ + // Check that relative paths can only be computed between paths + // which are either both absolute or both relative. + EXPECT_ERROR(path::relative("a", "/a")); + EXPECT_ERROR(path::relative("/a", "a")); + + // Check that a path relative to itself is an empty path. + ASSERT_SOME_EQ(".", path::relative("/a/b/c", "/a/b/c")); + ASSERT_SOME_EQ(".", path::relative("a/b/c", "a/b/c")); + + // Check for relative paths which do not require going up in the filesystem. + ASSERT_SOME_EQ("b", path::relative("/a/b", "/a")); + ASSERT_SOME_EQ("b", path::relative("a/b", "a")); + + // Check for relative paths which do require going up in the filesystem. + ASSERT_SOME_EQ("../../d/e", path::relative("/a/d/e", "/a/b/c")); + ASSERT_SOME_EQ("../../d/e", path::relative("a/d/e", "a/b/c")); + + // Check for behavior of not normalized paths. + ASSERT_SOME_EQ(".", path::relative("/a/./b", "/a/b")); +} + + TEST(PathTest, Comparison) { EXPECT_TRUE(Path("a") == Path("a"));
