Index: tools/gn/filesystem_utils.cc |
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc |
index c692425e19236ea0d13cf71f804dd41f9faf790e..a40fe69d20d281c588e6022bce1fba20014c4cc4 100644 |
--- a/tools/gn/filesystem_utils.cc |
+++ b/tools/gn/filesystem_utils.cc |
@@ -6,6 +6,7 @@ |
#include <algorithm> |
+#include "base/file_util.h" |
#include "base/logging.h" |
#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
@@ -109,6 +110,59 @@ bool DoesBeginWindowsDriveLetter(const base::StringPiece& path) { |
} |
#endif |
+// A wrapper around FilePath.GetComponents that works the way we need. This is |
+// not super efficient since it does some O9n) transformations on the path. If |
Dirk Pranke
2014/02/18 19:22:35
typo: O9n) -> O(n)
|
+// this is called a lot, we might want to optimize. |
+std::vector<base::FilePath::StringType> GetPathComponents( |
+ const base::FilePath& path) { |
+ std::vector<base::FilePath::StringType> result; |
+ path.GetComponents(&result); |
+ |
+ if (result.empty()) |
+ return result; |
+ |
+ // GetComponents will preserve the "/" at the beginning, which confuses us. |
+ // We don't expect to have relative paths in this function. |
+ // Don't use IsSeparator since we always want to allow backslashes. |
+ if (result[0] == FILE_PATH_LITERAL("/") || |
+ result[0] == FILE_PATH_LITERAL("\\")) |
+ result.erase(result.begin()); |
+ |
+#if defined(OS_WIN) |
+ // On Windows, GetComponents will give us [ "C:", "/", "foo" ], and we |
+ // don't want the slash in there. This doesn't support input like "C:foo" |
+ // which means foo relative to the current directory of the C drive but |
+ // that's basically legacy DOS behavior we don't need to support. |
+ if (result.size() >= 2 && result[1] == L"/" || result[1] == L"\\") |
+ result.erase(result.begin() + 1); |
+#endif |
+ |
+ return result; |
+} |
+ |
+// Provides the equivalent of == for filesystem strings, trying to do |
+// approximately the right thing with case. |
+bool FilesystemStringsEqual(const base::FilePath::StringType& a, |
+ const base::FilePath::StringType& b) { |
+#if defined(OS_WIN) |
+ // Assume case-insesitive filesystems on Windows. We use the CompareString |
Dirk Pranke
2014/02/18 19:22:35
typo: case-insesitive -> case-insensitive.
|
+ // function to do a case-insensitive comparison based on the current locale |
+ // (we don't want GN to depend on ICU which is large and requires data |
+ // files). This isn't perfect, but getting this perfectly right is very |
+ // difficult and requires I/O, and this comparison should cover 99.9999% of |
+ // all cases. |
+ // |
+ // Note: The documentation for CompareString says it runs fastest on |
+ // null-terminated strings with -1 passed for the length, so we do that here. |
+ // There should not be embedded nulls in filesystem strings. |
+ return ::CompareString(LOCALE_USER_DEFAULT, LINGUISTIC_IGNORECASE, |
+ a.c_str(), -1, b.c_str(), -1) == CSTR_EQUAL; |
+#else |
+ // Assume case-sensitive filesystems on non-Windows. |
+ return a == b; |
Dirk Pranke
2014/02/18 19:22:35
isn't Mac also case-insensitive by default? (thoug
brettw
2014/02/18 20:22:46
Hey, I didn't even know that. Let's see if we can
|
+#endif |
+} |
+ |
} // namespace |
SourceFileType GetSourceFileType(const SourceFile& file, |
@@ -564,6 +618,55 @@ std::string DirectoryWithNoLastSlash(const SourceDir& dir) { |
return ret; |
} |
+SourceDir SourceDirForPath(const base::FilePath& source_root, |
+ const base::FilePath& path) { |
+ std::vector<base::FilePath::StringType> source_comp = |
+ GetPathComponents(source_root); |
+ std::vector<base::FilePath::StringType> path_comp = |
+ GetPathComponents(path); |
+ |
+ // See if path is inside the source root by looking for each of source root's |
+ // components at the beginning of path. |
+ bool is_inside_source; |
+ if (path_comp.size() < source_comp.size()) { |
+ // Too small to fit. |
+ is_inside_source = false; |
+ } else { |
+ is_inside_source = true; |
+ for (size_t i = 0; i < source_comp.size(); i++) { |
+ if (!FilesystemStringsEqual(source_comp[i], path_comp[i])) { |
+ is_inside_source = false; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ std::string result_str; |
+ size_t initial_path_comp_to_use; |
+ if (is_inside_source) { |
+ // Construct a source-relative path beginning in // and skip all of the |
+ // shared directories. |
+ result_str = "//"; |
+ initial_path_comp_to_use = source_comp.size(); |
+ } else { |
+ // Not inside source code, construct a system-absolute path. |
+ result_str = "/"; |
+ initial_path_comp_to_use = 0; |
+ } |
+ |
+ for (size_t i = initial_path_comp_to_use; i < path_comp.size(); i++) { |
+ result_str.append(FilePathToUTF8(path_comp[i])); |
+ result_str.push_back('/'); |
+ } |
+ return SourceDir(result_str); |
+} |
+ |
+SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root) { |
+ base::FilePath cd; |
+ file_util::GetCurrentDirectory(&cd); |
+ return SourceDirForPath(source_root, cd); |
+} |
+ |
SourceDir GetToolchainOutputDir(const Settings* settings) { |
const OutputFile& toolchain_subdir = settings->toolchain_output_subdir(); |