OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/filesystem_utils.h" | 5 #include "tools/gn/filesystem_utils.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
| 9 #include "base/file_util.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
11 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
12 #include "build/build_config.h" | 13 #include "build/build_config.h" |
13 #include "tools/gn/location.h" | 14 #include "tools/gn/location.h" |
14 #include "tools/gn/settings.h" | 15 #include "tools/gn/settings.h" |
15 #include "tools/gn/source_dir.h" | 16 #include "tools/gn/source_dir.h" |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 if (!((path[0] >= 'A' && path[0] <= 'Z') || | 103 if (!((path[0] >= 'A' && path[0] <= 'Z') || |
103 path[0] >= 'a' && path[0] <= 'z')) | 104 path[0] >= 'a' && path[0] <= 'z')) |
104 return false; | 105 return false; |
105 | 106 |
106 if (path[2] != '/' && path[2] != '\\') | 107 if (path[2] != '/' && path[2] != '\\') |
107 return false; | 108 return false; |
108 return true; | 109 return true; |
109 } | 110 } |
110 #endif | 111 #endif |
111 | 112 |
| 113 // A wrapper around FilePath.GetComponents that works the way we need. This is |
| 114 // not super efficient since it does some O(n) transformations on the path. If |
| 115 // this is called a lot, we might want to optimize. |
| 116 std::vector<base::FilePath::StringType> GetPathComponents( |
| 117 const base::FilePath& path) { |
| 118 std::vector<base::FilePath::StringType> result; |
| 119 path.GetComponents(&result); |
| 120 |
| 121 if (result.empty()) |
| 122 return result; |
| 123 |
| 124 // GetComponents will preserve the "/" at the beginning, which confuses us. |
| 125 // We don't expect to have relative paths in this function. |
| 126 // Don't use IsSeparator since we always want to allow backslashes. |
| 127 if (result[0] == FILE_PATH_LITERAL("/") || |
| 128 result[0] == FILE_PATH_LITERAL("\\")) |
| 129 result.erase(result.begin()); |
| 130 |
| 131 #if defined(OS_WIN) |
| 132 // On Windows, GetComponents will give us [ "C:", "/", "foo" ], and we |
| 133 // don't want the slash in there. This doesn't support input like "C:foo" |
| 134 // which means foo relative to the current directory of the C drive but |
| 135 // that's basically legacy DOS behavior we don't need to support. |
| 136 if (result.size() >= 2 && result[1] == L"/" || result[1] == L"\\") |
| 137 result.erase(result.begin() + 1); |
| 138 #endif |
| 139 |
| 140 return result; |
| 141 } |
| 142 |
| 143 // Provides the equivalent of == for filesystem strings, trying to do |
| 144 // approximately the right thing with case. |
| 145 bool FilesystemStringsEqual(const base::FilePath::StringType& a, |
| 146 const base::FilePath::StringType& b) { |
| 147 #if defined(OS_WIN) |
| 148 // Assume case-insensitive filesystems on Windows. We use the CompareString |
| 149 // function to do a case-insensitive comparison based on the current locale |
| 150 // (we don't want GN to depend on ICU which is large and requires data |
| 151 // files). This isn't perfect, but getting this perfectly right is very |
| 152 // difficult and requires I/O, and this comparison should cover 99.9999% of |
| 153 // all cases. |
| 154 // |
| 155 // Note: The documentation for CompareString says it runs fastest on |
| 156 // null-terminated strings with -1 passed for the length, so we do that here. |
| 157 // There should not be embedded nulls in filesystem strings. |
| 158 return ::CompareString(LOCALE_USER_DEFAULT, LINGUISTIC_IGNORECASE, |
| 159 a.c_str(), -1, b.c_str(), -1) == CSTR_EQUAL; |
| 160 #else |
| 161 // Assume case-sensitive filesystems on non-Windows. |
| 162 return a == b; |
| 163 #endif |
| 164 } |
| 165 |
112 } // namespace | 166 } // namespace |
113 | 167 |
114 SourceFileType GetSourceFileType(const SourceFile& file, | 168 SourceFileType GetSourceFileType(const SourceFile& file, |
115 Settings::TargetOS os) { | 169 Settings::TargetOS os) { |
116 base::StringPiece extension = FindExtension(&file.value()); | 170 base::StringPiece extension = FindExtension(&file.value()); |
117 if (extension == "cc" || extension == "cpp" || extension == "cxx") | 171 if (extension == "cc" || extension == "cpp" || extension == "cxx") |
118 return SOURCE_CC; | 172 return SOURCE_CC; |
119 if (extension == "h") | 173 if (extension == "h") |
120 return SOURCE_H; | 174 return SOURCE_H; |
121 if (extension == "c") | 175 if (extension == "c") |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 ret.assign("/."); | 611 ret.assign("/."); |
558 } else if (dir.value() == "//") { | 612 } else if (dir.value() == "//") { |
559 ret.assign("//."); | 613 ret.assign("//."); |
560 } else { | 614 } else { |
561 ret.assign(dir.value()); | 615 ret.assign(dir.value()); |
562 ret.resize(ret.size() - 1); | 616 ret.resize(ret.size() - 1); |
563 } | 617 } |
564 return ret; | 618 return ret; |
565 } | 619 } |
566 | 620 |
| 621 SourceDir SourceDirForPath(const base::FilePath& source_root, |
| 622 const base::FilePath& path) { |
| 623 std::vector<base::FilePath::StringType> source_comp = |
| 624 GetPathComponents(source_root); |
| 625 std::vector<base::FilePath::StringType> path_comp = |
| 626 GetPathComponents(path); |
| 627 |
| 628 // See if path is inside the source root by looking for each of source root's |
| 629 // components at the beginning of path. |
| 630 bool is_inside_source; |
| 631 if (path_comp.size() < source_comp.size()) { |
| 632 // Too small to fit. |
| 633 is_inside_source = false; |
| 634 } else { |
| 635 is_inside_source = true; |
| 636 for (size_t i = 0; i < source_comp.size(); i++) { |
| 637 if (!FilesystemStringsEqual(source_comp[i], path_comp[i])) { |
| 638 is_inside_source = false; |
| 639 break; |
| 640 } |
| 641 } |
| 642 } |
| 643 |
| 644 std::string result_str; |
| 645 size_t initial_path_comp_to_use; |
| 646 if (is_inside_source) { |
| 647 // Construct a source-relative path beginning in // and skip all of the |
| 648 // shared directories. |
| 649 result_str = "//"; |
| 650 initial_path_comp_to_use = source_comp.size(); |
| 651 } else { |
| 652 // Not inside source code, construct a system-absolute path. |
| 653 result_str = "/"; |
| 654 initial_path_comp_to_use = 0; |
| 655 } |
| 656 |
| 657 for (size_t i = initial_path_comp_to_use; i < path_comp.size(); i++) { |
| 658 result_str.append(FilePathToUTF8(path_comp[i])); |
| 659 result_str.push_back('/'); |
| 660 } |
| 661 return SourceDir(result_str); |
| 662 } |
| 663 |
| 664 SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root) { |
| 665 base::FilePath cd; |
| 666 file_util::GetCurrentDirectory(&cd); |
| 667 return SourceDirForPath(source_root, cd); |
| 668 } |
| 669 |
567 SourceDir GetToolchainOutputDir(const Settings* settings) { | 670 SourceDir GetToolchainOutputDir(const Settings* settings) { |
568 const OutputFile& toolchain_subdir = settings->toolchain_output_subdir(); | 671 const OutputFile& toolchain_subdir = settings->toolchain_output_subdir(); |
569 | 672 |
570 std::string result = settings->build_settings()->build_dir().value(); | 673 std::string result = settings->build_settings()->build_dir().value(); |
571 if (!toolchain_subdir.value().empty()) | 674 if (!toolchain_subdir.value().empty()) |
572 result.append(toolchain_subdir.value()); | 675 result.append(toolchain_subdir.value()); |
573 | 676 |
574 return SourceDir(SourceDir::SWAP_IN, &result); | 677 return SourceDir(SourceDir::SWAP_IN, &result); |
575 } | 678 } |
576 | 679 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
624 return GetGenDirForSourceDir(target->settings(), target->label().dir()); | 727 return GetGenDirForSourceDir(target->settings(), target->label().dir()); |
625 } | 728 } |
626 | 729 |
627 SourceDir GetCurrentOutputDir(const Scope* scope) { | 730 SourceDir GetCurrentOutputDir(const Scope* scope) { |
628 return GetOutputDirForSourceDir(scope->settings(), scope->GetSourceDir()); | 731 return GetOutputDirForSourceDir(scope->settings(), scope->GetSourceDir()); |
629 } | 732 } |
630 | 733 |
631 SourceDir GetCurrentGenDir(const Scope* scope) { | 734 SourceDir GetCurrentGenDir(const Scope* scope) { |
632 return GetGenDirForSourceDir(scope->settings(), scope->GetSourceDir()); | 735 return GetGenDirForSourceDir(scope->settings(), scope->GetSourceDir()); |
633 } | 736 } |
OLD | NEW |