• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(const 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(const std::string& 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(const 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(const 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(const std::string_view& source_root,
116                                         const 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                    const 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(
151     const std::string& input,
152     const SourceDir& dest_dir,
153     const std::string_view& source_root = std::string_view());
154 
155 // Resolves a file or dir name (parameter input) relative to
156 // value directory. Will return an empty SourceDir/File on error
157 // and set the give *err pointer (required). Empty input is always an error.
158 // Returned value can be used to set value in either SourceFile or SourceDir
159 // (based on as_file parameter).
160 //
161 // Parameter as_file defines whether result path will look like a file path
162 // or it should be treated as a directory (contains "/" and the end
163 // of the string).
164 //
165 // If source_root is supplied, these functions will additionally handle the
166 // case where the input is a system-absolute but still inside the source
167 // tree. This is the case for some external tools.
168 template <typename StringType>
169 std::string ResolveRelative(const StringType& input,
170                             const std::string& value,
171                             bool as_file,
172                             const std::string_view& source_root);
173 
174 // Resolves source file or directory relative to some given source root. Returns
175 // an empty file path on error.
176 base::FilePath ResolvePath(const std::string& value,
177                            bool as_file,
178                            const base::FilePath& source_root);
179 
180 // Returns the given directory with no terminating slash at the end, such that
181 // appending a slash and more stuff will produce a valid path.
182 //
183 // If the directory refers to either the source or system root, we'll append
184 // a "." so this remains valid.
185 std::string DirectoryWithNoLastSlash(const SourceDir& dir);
186 
187 // Returns the "best" SourceDir representing the given path. If it's inside the
188 // given source_root, a source-relative directory will be returned (e.g.
189 // "//foo/bar.cc". If it's outside of the source root or the source root is
190 // empty, a system-absolute directory will be returned.
191 SourceDir SourceDirForPath(const base::FilePath& source_root,
192                            const base::FilePath& path);
193 
194 // Like SourceDirForPath but returns the SourceDir representing the current
195 // directory.
196 SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root);
197 
198 // Given the label of a toolchain and whether that toolchain is the default
199 // toolchain, returns the name of the subdirectory for that toolchain's
200 // output. This will be the empty string to indicate that the toolchain outputs
201 // go in the root build directory. Otherwise, the result will end in a slash.
202 std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default);
203 
204 // Returns true if the contents of the file and stream given are equal, false
205 // otherwise.
206 bool ContentsEqual(const base::FilePath& file_path, const std::string& data);
207 
208 // Writes given stream contents to the given file if it differs from existing
209 // file contents. Returns true if new contents was successfully written or
210 // existing file contents doesn't need updating, false on write error. |err| is
211 // set on write error if not nullptr.
212 bool WriteFileIfChanged(const base::FilePath& file_path,
213                         const std::string& data,
214                         Err* err);
215 
216 // Writes given stream contents to the given file. Returns true if data was
217 // successfully written, false otherwise. |err| is set on error if not nullptr.
218 bool WriteFile(const base::FilePath& file_path,
219                const std::string& data,
220                Err* err);
221 
222 // -----------------------------------------------------------------------------
223 
224 enum class BuildDirType {
225   // Returns the root toolchain dir rather than the generated or output
226   // subdirectories. This is valid only for the toolchain directory getters.
227   // Asking for this for a target or source dir makes no sense.
228   TOOLCHAIN_ROOT,
229 
230   // Generated file directory.
231   GEN,
232 
233   // Output file directory.
234   OBJ,
235 };
236 
237 // In different contexts, different information is known about the toolchain in
238 // question. If you have a Target or settings object, everything can be
239 // extracted from there. But when querying label information on something in
240 // another toolchain, for example, the only thing known (it may not even exist)
241 // is the toolchain label string and whether it matches the default toolchain.
242 //
243 // This object extracts the relevant information from a variety of input
244 // types for the convenience of the caller.
245 class BuildDirContext {
246  public:
247   // Extracts toolchain information associated with the given target.
248   explicit BuildDirContext(const Target* target);
249 
250   // Extracts toolchain information associated with the given settings object.
251   explicit BuildDirContext(const Settings* settings);
252 
253   // Extrats toolchain information from the current toolchain of the scope.
254   explicit BuildDirContext(const Scope* execution_scope);
255 
256   // Extracts the default toolchain information from the given execution
257   // scope. The toolchain you want to query must be passed in. This doesn't
258   // use the settings object from the Scope so one can query other toolchains.
259   // If you want to use the scope's current toolchain, use the version above.
260   BuildDirContext(const Scope* execution_scope, const Label& toolchain_label);
261 
262   // Specify all information manually.
263   BuildDirContext(const BuildSettings* build_settings,
264                   const Label& toolchain_label,
265                   bool is_default_toolchain);
266 
267   const BuildSettings* build_settings;
268   const Label& toolchain_label;
269   bool is_default_toolchain;
270 };
271 
272 // Returns the root, object, or generated file directory for the toolchain.
273 //
274 // The toolchain object file root is never exposed in GN (there is no
275 // root_obj_dir variable) so BuildDirType::OBJ would normally never be passed
276 // to this function except when it's called by one of the variants below that
277 // append paths to it.
278 SourceDir GetBuildDirAsSourceDir(const BuildDirContext& context,
279                                  BuildDirType type);
280 OutputFile GetBuildDirAsOutputFile(const BuildDirContext& context,
281                                    BuildDirType type);
282 
283 // Returns the output or generated file directory corresponding to the given
284 // source directory.
285 SourceDir GetSubBuildDirAsSourceDir(const BuildDirContext& context,
286                                     const SourceDir& source_dir,
287                                     BuildDirType type);
288 OutputFile GetSubBuildDirAsOutputFile(const BuildDirContext& context,
289                                       const SourceDir& source_dir,
290                                       BuildDirType type);
291 
292 // Returns the output or generated file directory corresponding to the given
293 // target.
294 SourceDir GetBuildDirForTargetAsSourceDir(const Target* target,
295                                           BuildDirType type);
296 OutputFile GetBuildDirForTargetAsOutputFile(const Target* target,
297                                             BuildDirType type);
298 
299 // Returns the scope's current directory.
300 SourceDir GetScopeCurrentBuildDirAsSourceDir(const Scope* scope,
301                                              BuildDirType type);
302 // Lack of OutputDir version is due only to it not currently being needed,
303 // please add one if you need it.
304 
305 #endif  // TOOLS_GN_FILESYSTEM_UTILS_H_
306