]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
refactor: fs::path-ify ignore_header_paths and related functions
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 3 Aug 2023 06:44:21 +0000 (08:44 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 3 Aug 2023 08:43:53 +0000 (10:43 +0200)
16 files changed:
src/Context.hpp
src/Util.cpp
src/Util.hpp
src/ccache.cpp
src/ccache.hpp
src/execute.cpp
src/execute.hpp
src/hashutil.cpp
src/util/path.cpp
src/util/path.hpp
src/util/string.cpp
src/util/string.hpp
unittest/test_Util.cpp
unittest/test_ccache.cpp
unittest/test_util_path.cpp
unittest/test_util_string.cpp

index 7f3535fecf87d4b540e7b2995f97cb7bb1df4454..bfc92a4235a841107aac23f059e812cb48354087 100644 (file)
@@ -86,7 +86,7 @@ public:
   util::Bytes cpp_stderr_data;
 
   // Headers (or directories with headers) to ignore in manifest mode.
-  std::vector<std::string> ignore_header_paths;
+  std::vector<std::filesystem::path> ignore_header_paths;
 
   // Storage (fronting local and remote storage backends).
   storage::Storage storage;
index bbebbc621d62b593a414d3cc3c7ce48892b1fd4d..cdd83c031c403013afbcc19a144c39c34b1bb9ed 100644 (file)
@@ -290,18 +290,6 @@ make_relative_path(const Context& ctx, std::string_view path)
     ctx.config.base_dir(), ctx.actual_cwd, ctx.apparent_cwd, path);
 }
 
-bool
-matches_dir_prefix_or_file(std::string_view dir_prefix_or_file,
-                           std::string_view path)
-{
-  return !dir_prefix_or_file.empty() && !path.empty()
-         && dir_prefix_or_file.length() <= path.length()
-         && util::starts_with(path, dir_prefix_or_file)
-         && (dir_prefix_or_file.length() == path.length()
-             || is_dir_separator(path[dir_prefix_or_file.length()])
-             || is_dir_separator(dir_prefix_or_file.back()));
-}
-
 static std::string
 do_normalize_abstract_absolute_path(std::string_view path)
 {
index 6648cb7d6fbc71c6de0a05784433f765770f71be..6159390f0acd51559f25f06780c34cd785cd9778 100644 (file)
@@ -97,11 +97,6 @@ std::string make_relative_path(const std::string& base_dir,
 // Like above but with base directory and apparent/actual CWD taken from `ctx`.
 std::string make_relative_path(const Context& ctx, std::string_view path);
 
-// Return whether `path` is equal to `dir_prefix_or_file` or if
-// `dir_prefix_or_file` is a directory prefix of `path`.
-bool matches_dir_prefix_or_file(std::string_view dir_prefix_or_file,
-                                std::string_view path);
-
 // Normalize absolute path `path`, not taking symlinks into account.
 //
 // Normalization here means syntactically removing redundant slashes and
index 705878fd27b5f2df454873dce44a450d94fdf32a..378a0867c561ba0c544a5b3043c212e6d4640032 100644 (file)
@@ -368,7 +368,7 @@ do_remember_include_file(Context& ctx,
   }
 
   for (const auto& ignore_header_path : ctx.ignore_header_paths) {
-    if (Util::matches_dir_prefix_or_file(ignore_header_path, path)) {
+    if (file_path_matches_dir_prefix_or_file(ignore_header_path, path)) {
       return true;
     }
   }
@@ -1540,11 +1540,11 @@ hash_common_info(const Context& ctx,
   }
 
   if (!ctx.config.extra_files_to_hash().empty()) {
-    for (const std::string& path :
+    for (const auto& path :
          util::split_path_list(ctx.config.extra_files_to_hash())) {
       LOG("Hashing extra file {}", path);
       hash.hash_delimiter("extrafile");
-      if (!hash_binary_file(ctx, hash, path)) {
+      if (!hash_binary_file(ctx, hash, path.string())) {
         return tl::unexpected(Statistic::error_hashing_extra_file);
       }
     }
@@ -2677,6 +2677,21 @@ is_ccache_executable(const fs::path& path)
   return util::starts_with(name, "ccache");
 }
 
+bool
+file_path_matches_dir_prefix_or_file(const fs::path& dir_prefix_or_file,
+                                     const fs::path& file_path)
+{
+  DEBUG_ASSERT(!dir_prefix_or_file.empty());
+  DEBUG_ASSERT(!file_path.filename().empty());
+
+  auto end = std::mismatch(dir_prefix_or_file.begin(),
+                           dir_prefix_or_file.end(),
+                           file_path.begin(),
+                           file_path.end())
+               .first;
+  return end == dir_prefix_or_file.end() || end->empty();
+}
+
 int
 ccache_main(int argc, const char* const* argv)
 {
index 7fe12359ad8f8c6b475460fefa2f425f4522a6b8..c085c02db218cf4e658f4ef36ba8d934b1fea7e8 100644 (file)
@@ -52,5 +52,11 @@ ArgvParts split_argv(int argc, const char* const* argv);
 void find_compiler(Context& ctx,
                    const FindExecutableFunction& find_executable_function,
                    bool masquerading_as_compiler);
+
 CompilerType guess_compiler(std::string_view path);
+
 bool is_ccache_executable(const std::filesystem::path& path);
+
+bool file_path_matches_dir_prefix_or_file(
+  const std::filesystem::path& dir_prefix_or_file,
+  const std::filesystem::path& file_path);
index 1c716469200cd4393c63ffc4ff16ab7ef33dcd9b..8e04eddce5701404f9d2f22c6e1f0efc0716da21 100644 (file)
@@ -33,6 +33,7 @@
 #include <fmtmacros.hpp>
 #include <util/DirEntry.hpp>
 #include <util/file.hpp>
+#include <util/filesystem.hpp>
 #include <util/path.hpp>
 #include <util/string.hpp>
 #include <util/wincompat.hpp>
@@ -51,6 +52,8 @@
 #  include "Finalizer.hpp"
 #endif
 
+namespace fs = util::filesystem;
+
 #ifdef _WIN32
 static int win32execute(const char* path,
                         const char* const* argv,
@@ -84,7 +87,7 @@ win32getshell(const std::string& path)
   const char* path_list = getenv("PATH");
   std::string sh;
   if (util::to_lowercase(Util::get_extension(path)) == ".sh" && path_list) {
-    sh = find_executable_in_path("sh.exe", path_list);
+    sh = find_executable_in_path("sh.exe", path_list).string();
   }
   if (sh.empty() && getenv("CCACHE_DETECT_SHEBANG")) {
     // Detect shebang.
@@ -93,7 +96,7 @@ win32getshell(const std::string& path)
       char buf[10] = {0};
       fgets(buf, sizeof(buf) - 1, fp.get());
       if (std::string(buf) == "#!/bin/sh" && path_list) {
-        sh = find_executable_in_path("sh.exe", path_list);
+        sh = find_executable_in_path("sh.exe", path_list).string();
       }
     }
   }
@@ -356,28 +359,28 @@ find_executable(const Context& ctx,
     return {};
   }
 
-  return find_executable_in_path(name, path_list, exclude_path);
+  return find_executable_in_path(name, path_list, exclude_path).string();
 }
 
-std::string
+fs::path
 find_executable_in_path(const std::string& name,
                         const std::string& path_list,
-                        std::optional<std::string> exclude_path)
+                        const std::optional<fs::path>& exclude_path)
 {
   if (path_list.empty()) {
     return {};
   }
 
-  const auto real_exclude_path =
-    exclude_path ? util::real_path(*exclude_path) : "";
+  auto real_exclude_path =
+    exclude_path ? fs::canonical(*exclude_path).value_or("") : "";
 
   // Search the path list looking for the first compiler of the right name that
   // isn't us.
-  for (const std::string& dir : util::split_path_list(path_list)) {
-    const std::vector<std::string> candidates = {
-      FMT("{}/{}", dir, name),
+  for (const auto& dir : util::split_path_list(path_list)) {
+    const std::vector<fs::path> candidates = {
+      dir / name,
 #ifdef _WIN32
-      FMT("{}/{}.exe", dir, name),
+      dir / FMT("{}.exe", name),
 #endif
     };
     for (const auto& candidate : candidates) {
@@ -398,9 +401,9 @@ find_executable_in_path(const std::string& name,
         access(candidate.c_str(), X_OK) == 0;
 #endif
       if (candidate_exists) {
-        const auto real_candidate = util::real_path(candidate);
-        if ((real_exclude_path.empty() || real_candidate != real_exclude_path)
-            && !is_ccache_executable(real_candidate)) {
+        auto real_candidate = fs::canonical(candidate);
+        if (real_candidate && *real_candidate != real_exclude_path
+            && !is_ccache_executable(*real_candidate)) {
           return candidate;
         }
       }
index c44a465abefd9272fb7d54fb191bbeaf53a0c9ae..5d0527dfbb8d4142a7ce472b3da6e898f7880fe6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2023 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -20,6 +20,7 @@
 
 #include "Fd.hpp"
 
+#include <filesystem>
 #include <optional>
 #include <string>
 
@@ -35,10 +36,10 @@ std::string find_executable(const Context& ctx,
                             const std::string& name,
                             const std::string& exclude_path);
 
-std::string
-find_executable_in_path(const std::string& name,
-                        const std::string& path_list,
-                        std::optional<std::string> exclude_path = std::nullopt);
+std::filesystem::path find_executable_in_path(
+  const std::string& name,
+  const std::string& path_list,
+  const std::optional<std::filesystem::path>& exclude_path = std::nullopt);
 
 #ifdef _WIN32
 std::string win32getshell(const std::string& path);
index 0cd4265c7c70bd87f4e8a0a3c99832771df3c7ae..fc43e87640581738fdff61eebc14b042feeaeb54 100644 (file)
@@ -382,7 +382,7 @@ hash_command_output(Hash& hash,
   STARTUPINFO si;
   memset(&si, 0x00, sizeof(si));
 
-  std::string path = find_executable_in_path(args[0], getenv("PATH"));
+  auto path = find_executable_in_path(args[0], getenv("PATH")).string();
   if (path.empty()) {
     path = args[0];
   }
index 019d3965660f2c1e6c9d5a6382cf8dac16dbf5d2..c9891d6e7d9fe739413ce12f6251d1114271dcf9 100644 (file)
 
 #ifdef _WIN32
 const char k_dev_null_path[] = "nul:";
-const char k_path_delimiter[] = ";";
 #else
 const char k_dev_null_path[] = "/dev/null";
-const char k_path_delimiter[] = ":";
 #endif
 
 namespace fs = util::filesystem;
@@ -130,12 +128,6 @@ real_path(std::string_view path)
   return real_path ? real_path->string() : std::string(path);
 }
 
-std::vector<std::string>
-split_path_list(std::string_view path_list)
-{
-  return split_into_strings(path_list, k_path_delimiter);
-}
-
 std::string
 to_absolute_path(std::string_view path)
 {
index ccd92a2c038e725c8a6207163a875f0b5c901dba..02b790e475d9bd9ab9975bfd12392a0189fcf075 100644 (file)
@@ -57,10 +57,6 @@ bool path_starts_with(std::string_view path, std::string_view prefix);
 // doesn't exist) path is returned unmodified.
 std::string real_path(std::string_view path);
 
-// Split a list of paths (such as the content of $PATH on Unix platforms or
-// %PATH% on Windows platforms) into paths.
-std::vector<std::string> split_path_list(std::string_view path_list);
-
 // Make `path` an absolute path.
 std::string to_absolute_path(std::string_view path);
 
index a154d09388e6a8cb16f25899a61f2df449eea2d5..cf621e83d8d8b24daf02fcd27ecfc14cb54a7dee 100644 (file)
@@ -429,6 +429,20 @@ split_once(const std::string_view string, const char split_char)
   }
 }
 
+std::vector<std::filesystem::path>
+split_path_list(std::string_view path_list)
+{
+#ifdef _WIN32
+  const char path_delimiter[] = ";";
+#else
+  const char path_delimiter[] = ":";
+#endif
+  auto strings = split_into_views(path_list, path_delimiter);
+  std::vector<std::filesystem::path> paths;
+  std::copy(strings.cbegin(), strings.cend(), std::back_inserter(paths));
+  return paths;
+}
+
 std::string
 strip_whitespace(const std::string_view string)
 {
index c3c207a82245af03f55d5e785b09f909c8bbf049..3b263651adf4c684ca77a1cbd154df070bf23e5a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <cstdint>
 #include <cstring>
+#include <filesystem>
 #include <optional>
 #include <string>
 #include <string_view>
@@ -171,6 +172,10 @@ split_once(std::string&& string, char split_char);
 std::pair<std::string_view, std::optional<std::string_view>>
 split_once(std::string_view string, char split_char);
 
+// Split a list of paths (such as the content of $PATH on Unix platforms or
+// %PATH% on Windows platforms) into paths.
+std::vector<std::filesystem::path> split_path_list(std::string_view path_list);
+
 // Return true if `prefix` is a prefix of `string`.
 bool starts_with(const char* string, std::string_view prefix);
 
index 52f182ad0ff9675ffee588fb39960fcf1e22a57d..f0c355bb19611414108208c5bf20c2098459fde7 100644 (file)
@@ -252,35 +252,6 @@ TEST_CASE("Util::make_relative_path")
 #endif
 }
 
-TEST_CASE("Util::matches_dir_prefix_or_file")
-{
-  CHECK(!Util::matches_dir_prefix_or_file("", ""));
-  CHECK(!Util::matches_dir_prefix_or_file("/", ""));
-  CHECK(!Util::matches_dir_prefix_or_file("", "/"));
-
-  CHECK(Util::matches_dir_prefix_or_file("aa", "aa"));
-  CHECK(!Util::matches_dir_prefix_or_file("aaa", "aa"));
-  CHECK(!Util::matches_dir_prefix_or_file("aa", "aaa"));
-  CHECK(!Util::matches_dir_prefix_or_file("aa/", "aa"));
-
-  CHECK(Util::matches_dir_prefix_or_file("/aa/bb", "/aa/bb"));
-  CHECK(!Util::matches_dir_prefix_or_file("/aa/b", "/aa/bb"));
-  CHECK(!Util::matches_dir_prefix_or_file("/aa/bbb", "/aa/bb"));
-
-  CHECK(Util::matches_dir_prefix_or_file("/aa", "/aa/bb"));
-  CHECK(Util::matches_dir_prefix_or_file("/aa/", "/aa/bb"));
-  CHECK(!Util::matches_dir_prefix_or_file("/aa/bb", "/aa"));
-  CHECK(!Util::matches_dir_prefix_or_file("/aa/bb", "/aa/"));
-
-#ifdef _WIN32
-  CHECK(Util::matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
-  CHECK(Util::matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
-#else
-  CHECK(!Util::matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
-  CHECK(!Util::matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
-#endif
-}
-
 TEST_CASE("Util::normalize_abstract_absolute_path")
 {
   CHECK(Util::normalize_abstract_absolute_path("") == "");
index 9e098bfbd874a27a4375a50af36e15df0dae24ee..e0172a5688d1a19a4b2d5ae1f3eee60616f22e71 100644 (file)
@@ -219,4 +219,28 @@ TEST_CASE("is_ccache_executable")
 #endif
 }
 
+TEST_CASE("file_path_matches_dir_prefix_or_file")
+{
+  CHECK(file_path_matches_dir_prefix_or_file("aa", "aa"));
+  CHECK(!file_path_matches_dir_prefix_or_file("aaa", "aa"));
+  CHECK(!file_path_matches_dir_prefix_or_file("aa", "aaa"));
+  CHECK(file_path_matches_dir_prefix_or_file("aa/", "aa"));
+
+  CHECK(file_path_matches_dir_prefix_or_file("/aa/bb", "/aa/bb"));
+  CHECK(!file_path_matches_dir_prefix_or_file("/aa/b", "/aa/bb"));
+  CHECK(!file_path_matches_dir_prefix_or_file("/aa/bbb", "/aa/bb"));
+
+  CHECK(file_path_matches_dir_prefix_or_file("/aa", "/aa/bb"));
+  CHECK(file_path_matches_dir_prefix_or_file("/aa/", "/aa/bb"));
+  CHECK(!file_path_matches_dir_prefix_or_file("/aa/bb", "/aa"));
+
+#ifdef _WIN32
+  CHECK(file_path_matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
+  CHECK(file_path_matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
+#else
+  CHECK(!file_path_matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
+  CHECK(!file_path_matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
+#endif
+}
+
 TEST_SUITE_END();
index e7643019b7135273b9bc78d71dd74ddddb183e06..f781ff4e2d3e6cec886d0db15c4ff77a18ac80a8 100644 (file)
@@ -64,31 +64,6 @@ TEST_CASE("util::is_dev_null_path")
 #endif
 }
 
-TEST_CASE("util::split_path_list")
-{
-  CHECK(util::split_path_list("").empty());
-  {
-    const auto v = util::split_path_list("a");
-    REQUIRE(v.size() == 1);
-    CHECK(v[0] == "a");
-  }
-  {
-    const auto v = util::split_path_list("a/b");
-    REQUIRE(v.size() == 1);
-    CHECK(v[0] == "a/b");
-  }
-  {
-#ifdef _WIN32
-    const auto v = util::split_path_list("a/b;c");
-#else
-    const auto v = util::split_path_list("a/b:c");
-#endif
-    REQUIRE(v.size() == 2);
-    CHECK(v[0] == "a/b");
-    CHECK(v[1] == "c");
-  }
-}
-
 TEST_CASE("util::to_absolute_path")
 {
   CHECK(util::to_absolute_path("/foo/bar") == "/foo/bar");
index a36a77302c72066ef1c6b823a21af9143399c3d6..8410c8228fa499ac20eb338e7bc3447a33fa9453 100644 (file)
@@ -537,6 +537,31 @@ TEST_CASE("util::split_once")
   }
 }
 
+TEST_CASE("util::split_path_list")
+{
+  CHECK(util::split_path_list("").empty());
+  {
+    const auto v = util::split_path_list("a");
+    REQUIRE(v.size() == 1);
+    CHECK(v[0] == "a");
+  }
+  {
+    const auto v = util::split_path_list("a/b");
+    REQUIRE(v.size() == 1);
+    CHECK(v[0] == "a/b");
+  }
+  {
+#ifdef _WIN32
+    const auto v = util::split_path_list("a/b;c");
+#else
+    const auto v = util::split_path_list("a/b:c");
+#endif
+    REQUIRE(v.size() == 2);
+    CHECK(v[0] == "a/b");
+    CHECK(v[1] == "c");
+  }
+}
+
 TEST_CASE("util::starts_with")
 {
   // starts_with(const char*, string_view)