Merge topic 'path-resolver'

8dfc725cdb PathResolver: Add mode to collapse paths naively and look up on-disk case
75913fe430 PathResolver: Document in comments the on-disk case lookup on macOS

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !10438
This commit is contained in:
Brad King 2025-03-09 14:48:11 +00:00 committed by Kitware Robot
commit cd38131f31
4 changed files with 99 additions and 5 deletions

View File

@ -492,6 +492,14 @@ struct NaivePath
static constexpr Options::Symlinks Symlinks = Options::Symlinks::None;
static constexpr Options::Existence Existence = Options::Existence::Agnostic;
};
struct CasePath
{
#if defined(_WIN32) || defined(__APPLE__)
static constexpr Options::ActualCase ActualCase = Options::ActualCase::Yes;
#endif
static constexpr Options::Symlinks Symlinks = Options::Symlinks::None;
static constexpr Options::Existence Existence = Options::Existence::Agnostic;
};
struct RealPath
{
#if defined(_WIN32) || defined(__APPLE__)
@ -512,6 +520,8 @@ struct LogicalPath
#if defined(__SUNPRO_CC)
constexpr Options::Symlinks NaivePath::Symlinks;
constexpr Options::Existence NaivePath::Existence;
constexpr Options::Symlinks CasePath::Symlinks;
constexpr Options::Existence CasePath::Existence;
constexpr Options::Symlinks RealPath::Symlinks;
constexpr Options::Existence RealPath::Existence;
constexpr Options::Symlinks LogicalPath::Symlinks;
@ -535,6 +545,7 @@ System::~System() = default;
template class Resolver<Policies::LogicalPath>;
template class Resolver<Policies::RealPath>;
template class Resolver<Policies::CasePath>;
template class Resolver<Policies::NaivePath>;
}

View File

@ -78,13 +78,18 @@ namespace Policies {
/** Normalizes paths while resolving symlinks only when followed
by '..' components. Does not require paths to exist, but
reads on-disk case of paths that do exist (on Windows). */
reads on-disk case of paths that do exist (on Windows and macOS). */
struct LogicalPath;
/** Normalizes paths while resolving all symlinks.
Requires paths to exist, and reads their on-disk case (on Windows). */
/** Normalizes paths while resolving all symlinks. Requires paths to exist,
and reads their on-disk case (on Windows and macOS). */
struct RealPath;
/** Normalizes paths while assuming components followed by '..'
components are not symlinks. Does not require paths to exist, but
reads on-disk case of paths that do exist (on Windows and macOS). */
struct CasePath;
/** Normalizes paths in memory without disk access.
Assumes components followed by '..' components are not symlinks. */
struct NaivePath;
@ -94,6 +99,7 @@ struct NaivePath;
extern template class Resolver<Policies::LogicalPath>;
extern template class Resolver<Policies::RealPath>;
extern template class Resolver<Policies::CasePath>;
extern template class Resolver<Policies::NaivePath>;
}

View File

@ -441,9 +441,11 @@ public:
/** Convert an input path to an absolute path with no '/..' components.
Backslashes in the input path are converted to forward slashes.
Relative paths are interpreted w.r.t. GetLogicalWorkingDirectory.
On Windows, the on-disk capitalization is loaded for existing paths.
This is similar to 'realpath', but preserves symlinks that are
not erased by '../' components. */
not erased by '../' components.
On Windows and macOS, the on-disk capitalization is loaded for
existing paths. */
static std::string ToNormalizedPathOnDisk(std::string p);
#ifndef CMAKE_BOOTSTRAP

View File

@ -24,6 +24,7 @@
// IWYU pragma: no_forward_declare cm::PathResolver::Policies::LogicalPath
// IWYU pragma: no_forward_declare cm::PathResolver::Policies::NaivePath
// IWYU pragma: no_forward_declare cm::PathResolver::Policies::CasePath
// IWYU pragma: no_forward_declare cm::PathResolver::Policies::RealPath
namespace {
@ -212,6 +213,22 @@ bool posixSymlink()
{ "/1/2/3", { {}, {} } },
});
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("/link-a", "/link-a");
EXPECT_RESOLVE("/link-a-excess", "/link-a-excess");
EXPECT_RESOLVE("/link-a-excess/b", "/link-a-excess/b");
EXPECT_RESOLVE("/link-broken", "/link-broken");
EXPECT_RESOLVE("/link-a/../missing", "/missing");
EXPECT_RESOLVE("/a/b/link-c", "/a/b/link-c");
EXPECT_RESOLVE("/a/link-b/c", "/a/link-b/c");
EXPECT_RESOLVE("/a/link-b/link-c/..", "/a/link-b");
EXPECT_RESOLVE("/a/b/c/link-..|..", "/a/b/c/link-..|..");
EXPECT_RESOLVE("/a/b/c/link-..|../link-b", "/a/b/c/link-..|../link-b");
EXPECT_RESOLVE("/a/link-|1|2/3", "/a/link-|1|2/3");
EXPECT_RESOLVE("/a/link-|1|2/../2/3", "/a/2/3");
}
{
Resolver<Policies::LogicalPath> const r(os);
EXPECT_RESOLVE("/link-a", "/link-a");
@ -263,6 +280,16 @@ bool macosActualCase()
{ "/upper/link-c-upper", { "LINK-C-UPPER", "/upper" } },
});
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("/mIxEd/MiSsInG", "/MiXeD/MiSsInG");
EXPECT_RESOLVE("/mIxEd/link-MiXeD", "/MiXeD/LiNk-MiXeD");
EXPECT_RESOLVE("/mIxEd/link-c-MiXeD", "/MiXeD/LiNk-C-MiXeD");
EXPECT_RESOLVE("/upper/mIsSiNg", "/UPPER/mIsSiNg");
EXPECT_RESOLVE("/upper/link-upper", "/UPPER/LINK-UPPER");
EXPECT_RESOLVE("/upper/link-c-upper", "/UPPER/LINK-C-UPPER");
}
{
Resolver<Policies::LogicalPath> const r(os);
EXPECT_RESOLVE("/mIxEd/MiSsInG", "/MiXeD/MiSsInG");
@ -302,6 +329,16 @@ bool windowsRoot()
EXPECT_RESOLVE("C:/..", "C:/");
EXPECT_RESOLVE("c:/../", "c:/");
}
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("c:/", "C:/");
EXPECT_RESOLVE("C:/", "C:/");
EXPECT_RESOLVE("c://", "C:/");
EXPECT_RESOLVE("C:/.", "C:/");
EXPECT_RESOLVE("c:/./", "C:/");
EXPECT_RESOLVE("C:/..", "C:/");
EXPECT_RESOLVE("c:/../", "C:/");
}
os.SetPaths({
{ "c:/", { {}, {} } },
{ "//host/", { {}, {} } },
@ -360,6 +397,16 @@ bool windowsActualCase()
{ "c:/upper/link-c-upper", { "LINK-C-UPPER", "c:/upper" } },
});
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("c:/mIxEd/MiSsInG", "C:/MiXeD/MiSsInG");
EXPECT_RESOLVE("c:/mIxEd/link-MiXeD", "C:/MiXeD/LiNk-MiXeD");
EXPECT_RESOLVE("c:/mIxEd/link-c-MiXeD", "C:/MiXeD/LiNk-C-MiXeD");
EXPECT_RESOLVE("c:/upper/mIsSiNg", "C:/UPPER/mIsSiNg");
EXPECT_RESOLVE("c:/upper/link-upper", "C:/UPPER/LINK-UPPER");
EXPECT_RESOLVE("c:/upper/link-c-upper", "C:/UPPER/LINK-C-UPPER");
}
{
Resolver<Policies::LogicalPath> const r(os);
EXPECT_RESOLVE("c:/mIxEd/MiSsInG", "C:/MiXeD/MiSsInG");
@ -441,6 +488,27 @@ bool windowsWorkingDirectoryOnDrive()
EXPECT_RESOLVE("E:.", "E:/");
EXPECT_RESOLVE("E:..", "E:/");
}
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("c:", "C:/cwd");
EXPECT_RESOLVE("c:.", "C:/cwd");
EXPECT_RESOLVE("c:..", "C:/");
EXPECT_RESOLVE("C:", "C:/cwd");
EXPECT_RESOLVE("C:.", "C:/cwd");
EXPECT_RESOLVE("C:..", "C:/");
EXPECT_RESOLVE("d:", "D:/cwd-d");
EXPECT_RESOLVE("d:.", "D:/cwd-d");
EXPECT_RESOLVE("d:..", "D:/");
EXPECT_RESOLVE("D:", "D:/cwd-d");
EXPECT_RESOLVE("D:.", "D:/cwd-d");
EXPECT_RESOLVE("D:..", "D:/");
EXPECT_RESOLVE("e:", "E:/");
EXPECT_RESOLVE("e:.", "E:/");
EXPECT_RESOLVE("e:..", "E:/");
EXPECT_RESOLVE("E:", "E:/");
EXPECT_RESOLVE("E:.", "E:/");
EXPECT_RESOLVE("E:..", "E:/");
}
os.SetPaths({
{ "c:/", { {}, {} } },
{ "c:/cwd", { {}, {} } },
@ -496,6 +564,13 @@ bool windowsNetworkShare()
EXPECT_RESOLVE("link-to-host-share/..", "//host/");
EXPECT_RESOLVE("link-to-host-share/../missing", "//host/missing");
}
{
Resolver<Policies::CasePath> const r(os);
EXPECT_RESOLVE("link-to-host-share", "C:/cwd/link-to-host-share");
EXPECT_RESOLVE("link-to-host-share/..", "C:/cwd");
EXPECT_RESOLVE("link-to-host-share/../missing", "C:/cwd/missing");
}
return true;
}
#endif