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 O9n) transformations on the path. If | |
Dirk Pranke
2014/02/18 19:22:35
typo: O9n) -> O(n)
| |
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-insesitive filesystems on Windows. We use the CompareString | |
Dirk Pranke
2014/02/18 19:22:35
typo: case-insesitive -> case-insensitive.
| |
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; | |
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
| |
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 |