}
std::string
-make_relative_path(const Context& ctx, string_view path)
+make_relative_path(const std::string& base_dir,
+ const std::string& actual_cwd,
+ const std::string& apparent_cwd,
+ nonstd::string_view path)
{
- if (ctx.config.base_dir().empty()
- || !Util::starts_with(path, ctx.config.base_dir())) {
+ if (base_dir.empty() || !Util::starts_with(path, base_dir)) {
return std::string(path);
}
std::string path_str(path);
std::string normalized_path = Util::normalize_absolute_path(path_str);
std::vector<std::string> relpath_candidates = {
- Util::get_relative_path(ctx.actual_cwd, normalized_path),
+ Util::get_relative_path(actual_cwd, normalized_path),
};
- if (ctx.apparent_cwd != ctx.actual_cwd) {
+ if (apparent_cwd != actual_cwd) {
relpath_candidates.emplace_back(
- Util::get_relative_path(ctx.apparent_cwd, normalized_path));
+ Util::get_relative_path(apparent_cwd, normalized_path));
// Move best (= shortest) match first:
if (relpath_candidates[0].length() > relpath_candidates[1].length()) {
std::swap(relpath_candidates[0], relpath_candidates[1]);
return std::string(original_path);
}
+std::string
+make_relative_path(const Context& ctx, string_view path)
+{
+ return make_relative_path(
+ ctx.config.base_dir(), ctx.actual_cwd, ctx.apparent_cwd, path);
+}
+
bool
matches_dir_prefix_or_file(string_view dir_prefix_or_file, string_view path)
{
// time of day is used.
nonstd::optional<tm> localtime(nonstd::optional<time_t> time = {});
-// Make a relative path from current working directory to `path` if `path` is
-// under the base directory.
+// Make a relative path from current working directory (either `actual_cwd` or
+// `apparent_cwd`) to `path` if `path` is under `base_dir`.
+std::string make_relative_path(const std::string& base_dir,
+ const std::string& actual_cwd,
+ const std::string& apparent_cwd,
+ nonstd::string_view path);
+
+// Like above but with base directory and apparent/actual CWD taken from `ctx`.
std::string make_relative_path(const Context& ctx, nonstd::string_view path);
// Return whether `path` is equal to `dir_prefix_or_file` or if
#endif
}
+#ifndef _WIN32
+TEST_CASE("Util::make_relative_path")
+{
+ using Util::make_relative_path;
+
+ const TestContext test_context;
+
+ const std::string cwd = Util::get_actual_cwd();
+ const std::string actual_cwd = FMT("{}/d", cwd);
+ const std::string apparent_cwd = FMT("{}/s", cwd);
+
+ REQUIRE(Util::create_dir("d"));
+ REQUIRE(symlink("d", "s") == 0);
+ REQUIRE(chdir("s") == 0);
+ Util::setenv("PWD", apparent_cwd);
+
+ SUBCASE("No base directory")
+ {
+ CHECK(make_relative_path("", "/a", "/a", "/a/x") == "/a/x");
+ }
+
+ SUBCASE("Path matches neither actual nor apparent CWD")
+ {
+ CHECK(make_relative_path("/", "/a", "/b", "/x") == "/x");
+ }
+
+ SUBCASE("Match of actual CWD")
+ {
+ CHECK(make_relative_path("/", actual_cwd, apparent_cwd, actual_cwd + "/x")
+ == "./x");
+ }
+
+ SUBCASE("Match of apparent CWD")
+ {
+ CHECK(make_relative_path("/", actual_cwd, apparent_cwd, apparent_cwd + "/x")
+ == "./x");
+ }
+}
+#endif
+
TEST_CASE("Util::matches_dir_prefix_or_file")
{
CHECK(!Util::matches_dir_prefix_or_file("", ""));