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
3 // found in the LICENSE file.
4
5 #ifndef TOOLS_GN_FILESYSTEM_UTILS_H_
6 #define TOOLS_GN_FILESYSTEM_UTILS_H_
7
8 #include <stddef.h>
9
10 #include <string>
11 #include <string_view>
12
13 #include "base/files/file_path.h"
14 #include "gn/settings.h"
15 #include "gn/target.h"
16
17 class Err;
18
19 std::string FilePathToUTF8(const base::FilePath::StringType& str);
FilePathToUTF8(const base::FilePath & path)20 inline std::string FilePathToUTF8(const base::FilePath& path) {
21 return FilePathToUTF8(path.value());
22 }
23 base::FilePath UTF8ToFilePath(std::string_view sp);
24
25 // Extensions -----------------------------------------------------------------
26
27 // Returns the index of the extension (character after the last dot not after a
28 // slash). Returns std::string::npos if not found. Returns path.size() if the
29 // file ends with a dot.
30 size_t FindExtensionOffset(const std::string& path);
31
32 // Returns a string piece pointing into the input string identifying the
33 // extension. Note that the input pointer must outlive the output.
34 std::string_view FindExtension(const std::string* path);
35
36 // Filename parts -------------------------------------------------------------
37
38 // Returns the offset of the character following the last slash, or
39 // 0 if no slash was found. Returns path.size() if the path ends with a slash.
40 // Note that the input pointer must outlive the output.
41 size_t FindFilenameOffset(const std::string& path);
42
43 // Returns a string piece pointing into the input string identifying the
44 // file name (following the last slash, including the extension). Note that the
45 // input pointer must outlive the output.
46 std::string_view FindFilename(const std::string* path);
47
48 // Like FindFilename but does not include the extension.
49 std::string_view FindFilenameNoExtension(const std::string* path);
50
51 // Removes everything after the last slash. The last slash, if any, will be
52 // preserved.
53 void RemoveFilename(std::string* path);
54
55 // Returns if the given character is a slash. This allows both slashes and
56 // backslashes for consistency between Posix and Windows (as opposed to
57 // FilePath::IsSeparator which is based on the current platform).
IsSlash(const char ch)58 inline bool IsSlash(const char ch) {
59 return ch == '/' || ch == '\\';
60 }
61
62 // Returns true if the given path ends with a slash.
63 bool EndsWithSlash(std::string_view s);
64
65 // Path parts -----------------------------------------------------------------
66
67 // Returns a string piece pointing into the input string identifying the
68 // directory name of the given path, including the last slash. Note that the
69 // input pointer must outlive the output.
70 std::string_view FindDir(const std::string* path);
71
72 // Returns the substring identifying the last component of the dir, or the
73 // empty substring if none. For example "//foo/bar/" -> "bar".
74 std::string_view FindLastDirComponent(const SourceDir& dir);
75
76 // Returns true if the given string is in the given output dir. This is pretty
77 // stupid and doesn't handle "." and "..", etc., it is designed for a sanity
78 // check to keep people from writing output files to the source directory
79 // accidentally.
80 bool IsStringInOutputDir(const SourceDir& output_dir, const std::string& str);
81
82 // Verifies that the given string references a file inside of the given
83 // directory. This just uses IsStringInOutputDir above.
84 //
85 // The origin will be blamed in the error.
86 //
87 // If the file isn't in the dir, returns false and sets the error. Otherwise
88 // returns true and leaves the error untouched.
89 bool EnsureStringIsInOutputDir(const SourceDir& output_dir,
90 const std::string& str,
91 const ParseNode* origin,
92 Err* err);
93
94 // ----------------------------------------------------------------------------
95
96 // Returns true if the input string is absolute. Double-slashes at the
97 // beginning are treated as source-relative paths. On Windows, this handles
98 // paths of both the native format: "C:/foo" and ours "/C:/foo"
99 bool IsPathAbsolute(std::string_view path);
100
101 // Returns true if the input string is source-absolute. Source-absolute
102 // paths begin with two forward slashes and resolve as if they are
103 // relative to the source root.
104 bool IsPathSourceAbsolute(std::string_view path);
105
106 // Given an absolute path, checks to see if is it is inside the source root.
107 // If it is, fills a source-absolute path into the given output and returns
108 // true. If it isn't, clears the dest and returns false.
109 //
110 // The source_root should be a base::FilePath converted to UTF-8. On Windows,
111 // it should begin with a "C:/" rather than being our SourceFile's style
112 // ("/C:/"). The source root can end with a slash or not.
113 //
114 // Note that this does not attempt to normalize slashes in the output.
115 bool MakeAbsolutePathRelativeIfPossible(std::string_view source_root,
116 std::string_view path,
117 std::string* dest);
118
119 // Given two absolute paths |base| and |target|, returns a relative path to
120 // |target| as if the current directory was |base|. The relative path returned
121 // is minimal. For example, if "../../a/b/" and "../b" are both valid, then the
122 // latter will be returned. On Windows, it's impossible to have a relative path
123 // from C:\foo to D:\bar, so the absolute path |target| is returned instead for
124 // this case.
125 base::FilePath MakeAbsoluteFilePathRelativeIfPossible(
126 const base::FilePath& base,
127 const base::FilePath& target);
128
129 // Collapses "." and sequential "/"s and evaluates "..". |path| may be
130 // system-absolute, source-absolute, or relative. If |path| is source-absolute
131 // and |source_root| is non-empty, |path| may be system absolute after this
132 // function returns, if |path| references the filesystem outside of
133 // |source_root| (ex. path = "//.."). In this case on Windows, |path| will have
134 // a leading slash. Otherwise, |path| will retain its relativity. |source_root|
135 // must not end with a slash.
136 void NormalizePath(std::string* path,
137 std::string_view source_root = std::string_view());
138
139 // Converts slashes to backslashes for Windows. Keeps the string unchanged
140 // for other systems.
141 void ConvertPathToSystem(std::string* path);
142
143 // Takes a path, |input|, and makes it relative to the given directory
144 // |dest_dir|. Both inputs may be source-relative (e.g. begins with
145 // with "//") or may be absolute.
146 //
147 // If supplied, the |source_root| parameter is the absolute path to
148 // the source root and not end in a slash. Unless you know that the
149 // inputs are always source relative, this should be supplied.
150 std::string RebasePath(const std::string& input,
151 const SourceDir& dest_dir,
152 std::string_view source_root = std::string_view());
153
154 // Resolves a file or dir name (parameter input) relative to
155 // value directory. Will return an empty SourceDir/File on error
156 // and set the give *err pointer (required). Empty input is always an error.
157 // Returned value can be used to set value in either SourceFile or SourceDir
158 // (based on as_file parameter).
159 //
160 // Parameter as_file defines whether result path will look like a file path
161 // or it should be treated as a directory (contains "/" and the end
162 // of the string).
163 //
164 // If source_root is supplied, these functions will additionally handle the
165 // case where the input is a system-absolute but still inside the source
166 // tree. This is the case for some external tools.
167 std::string ResolveRelative(std::string_view input,
168 const std::string& value,
169 bool as_file,
170 std::string_view source_root);
171
172 // Resolves source file or directory relative to some given source root. Returns
173 // an empty file path on error.
174 base::FilePath ResolvePath(const std::string& value,
175 bool as_file,
176 const base::FilePath& source_root);
177
178 // Returns the given directory with no terminating slash at the end, such that
179 // appending a slash and more stuff will produce a valid path.
180 //
181 // If the directory refers to either the source or system root, we'll append
182 // a "." so this remains valid.
183 std::string DirectoryWithNoLastSlash(const SourceDir& dir);
184
185 // Returns the "best" SourceDir representing the given path. If it's inside the
186 // given source_root, a source-relative directory will be returned (e.g.
187 // "//foo/bar.cc". If it's outside of the source root or the source root is
188 // empty, a system-absolute directory will be returned.
189 SourceDir SourceDirForPath(const base::FilePath& source_root,
190 const base::FilePath& path);
191
192 // Like SourceDirForPath but returns the SourceDir representing the current
193 // directory.
194 SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root);
195
196 // Given the label of a toolchain and whether that toolchain is the default
197 // toolchain, returns the name of the subdirectory for that toolchain's
198 // output. This will be the empty string to indicate that the toolchain outputs
199 // go in the root build directory. Otherwise, the result will end in a slash.
200 std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default);
201
202 // Returns true if the contents of the file and stream given are equal, false
203 // otherwise.
204 bool ContentsEqual(const base::FilePath& file_path, const std::string& data);
205
206 // Writes given stream contents to the given file. Returns true if data was
207 // successfully written, false otherwise. |err| is set on error if not nullptr.
208 bool WriteFile(const base::FilePath& file_path,
209 const std::string& data,
210 Err* err);
211
212 // -----------------------------------------------------------------------------
213
214 enum class BuildDirType {
215 // Returns the root toolchain dir rather than the generated or output
216 // subdirectories. This is valid only for the toolchain directory getters.
217 // Asking for this for a target or source dir makes no sense.
218 TOOLCHAIN_ROOT,
219
220 // Generated file directory.
221 GEN,
222
223 // Output file directory.
224 OBJ,
225
226 // Phony file directory. As the name implies, this is not a real file
227 // directory, but a path that is used for the declaration of phony targets.
228 // This is done to avoid duplicate target names between real files and phony
229 // aliases that point to them.
230 PHONY,
231 };
232
233 // In different contexts, different information is known about the toolchain in
234 // question. If you have a Target or settings object, everything can be
235 // extracted from there. But when querying label information on something in
236 // another toolchain, for example, the only thing known (it may not even exist)
237 // is the toolchain label string and whether it matches the default toolchain.
238 //
239 // This object extracts the relevant information from a variety of input
240 // types for the convenience of the caller.
241 class BuildDirContext {
242 public:
243 // Extracts toolchain information associated with the given target.
244 explicit BuildDirContext(const Target* target);
245
246 // Extracts toolchain information associated with the given settings object.
247 explicit BuildDirContext(const Settings* settings);
248
249 // Extrats toolchain information from the current toolchain of the scope.
250 explicit BuildDirContext(const Scope* execution_scope);
251
252 // Extracts the default toolchain information from the given execution
253 // scope. The toolchain you want to query must be passed in. This doesn't
254 // use the settings object from the Scope so one can query other toolchains.
255 // If you want to use the scope's current toolchain, use the version above.
256 BuildDirContext(const Scope* execution_scope, const Label& toolchain_label);
257
258 // Specify all information manually.
259 BuildDirContext(const BuildSettings* build_settings,
260 const Label& toolchain_label,
261 bool is_default_toolchain);
262
263 const BuildSettings* build_settings;
264 const Label& toolchain_label;
265 bool is_default_toolchain;
266 };
267
268 // Returns the root, object, or generated file directory for the toolchain.
269 //
270 // The toolchain object file root is never exposed in GN (there is no
271 // root_obj_dir variable) so BuildDirType::OBJ would normally never be passed
272 // to this function except when it's called by one of the variants below that
273 // append paths to it.
274 SourceDir GetBuildDirAsSourceDir(const BuildDirContext& context,
275 BuildDirType type);
276 OutputFile GetBuildDirAsOutputFile(const BuildDirContext& context,
277 BuildDirType type);
278
279 // Returns the output or generated file directory corresponding to the given
280 // source directory.
281 SourceDir GetSubBuildDirAsSourceDir(const BuildDirContext& context,
282 const SourceDir& source_dir,
283 BuildDirType type);
284 OutputFile GetSubBuildDirAsOutputFile(const BuildDirContext& context,
285 const SourceDir& source_dir,
286 BuildDirType type);
287
288 // Returns the output or generated file directory corresponding to the given
289 // target.
290 SourceDir GetBuildDirForTargetAsSourceDir(const Target* target,
291 BuildDirType type);
292 OutputFile GetBuildDirForTargetAsOutputFile(const Target* target,
293 BuildDirType type);
294
295 // Returns the scope's current directory.
296 SourceDir GetScopeCurrentBuildDirAsSourceDir(const Scope* scope,
297 BuildDirType type);
298 // Lack of OutputDir version is due only to it not currently being needed,
299 // please add one if you need it.
300
301 #endif // TOOLS_GN_FILESYSTEM_UTILS_H_
302